Merge "Add tint color for dot icon"
diff --git a/Android.mk b/Android.mk
index e17fd0b..88be12f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -38,7 +38,9 @@
 include $(CLEAR_VARS)
 
 # FRAMEWORKS_BASE_SUBDIRS comes from build/core/pathmap.mk
-LOCAL_SRC_FILES := $(call find-other-java-files,$(FRAMEWORKS_BASE_SUBDIRS))
+LOCAL_SRC_FILES := \
+        $(call find-other-java-files,$(FRAMEWORKS_BASE_SUBDIRS)) \
+        $(call all-proto-files-under, core/proto)
 
 # EventLogTags files.
 LOCAL_SRC_FILES += \
@@ -145,6 +147,7 @@
 	core/java/android/content/ISyncStatusObserver.aidl \
 	core/java/android/content/pm/ILauncherApps.aidl \
 	core/java/android/content/pm/IOnAppsChangedListener.aidl \
+	core/java/android/content/pm/IOnPermissionsChangeListener.aidl \
 	core/java/android/content/pm/IOtaDexopt.aidl \
 	core/java/android/content/pm/IPackageDataObserver.aidl \
 	core/java/android/content/pm/IPackageDeleteObserver.aidl \
@@ -157,7 +160,7 @@
 	core/java/android/content/pm/IPackageManager.aidl \
 	core/java/android/content/pm/IPackageMoveObserver.aidl \
 	core/java/android/content/pm/IPackageStatsObserver.aidl \
-	core/java/android/content/pm/IOnPermissionsChangeListener.aidl \
+	core/java/android/content/pm/IPinItemRequest.aidl \
 	core/java/android/content/pm/IShortcutService.aidl \
 	core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl \
 	core/java/android/database/IContentObserver.aidl \
@@ -233,6 +236,9 @@
 	core/java/android/os/IDeviceIdentifiersPolicyService.aidl \
 	core/java/android/os/IDeviceIdleController.aidl \
 	core/java/android/os/IHardwarePropertiesManager.aidl \
+	core/java/android/os/IIncidentManager.aidl \
+	core/java/android/os/IIncidentReportCompletedListener.aidl \
+	core/java/android/os/IIncidentReportStatusListener.aidl \
 	core/java/android/os/IMaintenanceActivityListener.aidl \
 	core/java/android/os/IMessenger.aidl \
 	core/java/android/os/INetworkActivityListener.aidl \
@@ -527,6 +533,10 @@
     android.hardware.thermal@1.0-java-constants         \
     android.hardware.health@1.0-java-constants          \
 
+LOCAL_PROTOC_OPTIMIZE_TYPE := stream
+LOCAL_PROTOC_FLAGS := \
+    -Iexternal/protobuf/src
+
 LOCAL_MODULE := framework
 
 LOCAL_JACK_FLAGS := --multi-dex native
@@ -774,9 +784,6 @@
 # include definition of libcore_to_document
 include libcore/Docs.mk
 
-# include definition of junit_to_document
-include external/junit/Common.mk
-
 non_base_dirs := \
 	../opt/telephony/src/java/android/provider \
 	../opt/telephony/src/java/android/telephony \
@@ -817,8 +824,7 @@
 # Common sources for doc check and api check
 common_src_files := \
 	$(call find-other-html-files, $(html_dirs)) \
-	$(addprefix ../../, $(libcore_to_document)) \
-	$(addprefix ../../external/junit/, $(junit_to_document))
+	$(addprefix ../../, $(libcore_to_document))
 
 # These are relative to frameworks/base
 framework_docs_LOCAL_SRC_FILES := \
@@ -1388,6 +1394,35 @@
 
 include $(BUILD_JAVA_LIBRARY)
 
+# ====  c++ proto host library  ==============================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libplatformprotos
+LOCAL_PROTOC_OPTIMIZE_TYPE := full
+LOCAL_PROTOC_FLAGS := \
+    --include_source_info \
+    -Iexternal/protobuf/src
+LOCAL_SRC_FILES := \
+    $(call all-proto-files-under, core/proto) \
+    $(call all-proto-files-under, libs/incident/proto)
+LOCAL_C_INCLUDES := \
+    $(call generated-sources-dir-for,STATIC_LIBRARIES,libplatformprotos,)/proto
+LOCAL_EXPORT_C_INCLUDES := \
+    $(call generated-sources-dir-for,STATIC_LIBRARIES,libplatformprotos,)/proto
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+
+# ====  java proto host library  ==============================
+include $(CLEAR_VARS)
+LOCAL_MODULE := platformprotos
+LOCAL_PROTOC_OPTIMIZE_TYPE := full
+LOCAL_PROTOC_FLAGS := \
+    -Iexternal/protobuf/src
+LOCAL_SOURCE_FILES_ALL_GENERATED := true
+LOCAL_SRC_FILES := \
+    $(call all-proto-files-under, core/proto) \
+    $(call all-proto-files-under, libs/incident/proto)
+include $(BUILD_HOST_JAVA_LIBRARY)
+
 
 # Include subdirectory makefiles
 # ============================================================
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index c28db57..75de4a7 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,5 +1,5 @@
 [Hook Scripts]
-checkstyle_hook = ../../development/tools/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
+checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
                   -fw core/java/android/animation/
                       core/java/android/hardware/usb/
                       core/java/android/print/
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/OutlinePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/OutlinePerfTest.java
new file mode 100644
index 0000000..3a4fc72
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/OutlinePerfTest.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 android.graphics.perftests;
+
+import android.graphics.Outline;
+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 OutlinePerfTest {
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Test
+    public void testSetEmpty() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        Outline outline = new Outline();
+        while (state.keepRunning()) {
+            outline.setEmpty();
+        }
+    }
+
+    @Test
+    public void testSetRoundRect() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        Outline outline = new Outline();
+        while (state.keepRunning()) {
+            outline.setRoundRect(50, 50, 150, 150, 5);
+        }
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/PathPerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/PathPerfTest.java
new file mode 100644
index 0000000..7a49b4f
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/PathPerfTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.graphics.Path;
+import android.graphics.RectF;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.support.test.filters.LargeTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+@LargeTest
+public class PathPerfTest {
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Test
+    public void testReset() {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        Path path = new Path();
+        while (state.keepRunning()) {
+            path.reset();
+        }
+    }
+
+    @Test
+    public void testAddReset() {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        Path path = new Path();
+        while (state.keepRunning()) {
+            path.addRect(0, 0, 100, 100, Path.Direction.CW);
+            path.reset();
+        }
+    }
+
+    @Test
+    public void testRewind() {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        Path path = new Path();
+        while (state.keepRunning()) {
+            path.rewind();
+        }
+    }
+
+    @Test
+    public void testAddRewind() {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        Path path = new Path();
+        while (state.keepRunning()) {
+            path.addRect(0, 0, 100, 100, Path.Direction.CW);
+            path.rewind();
+        }
+    }
+
+    @Test
+    public void testIsEmpty() {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        Path path = new Path();
+        path.addRect(0, 0, 100, 100, Path.Direction.CW);
+        while (state.keepRunning()) {
+            path.isEmpty();
+        }
+    }
+
+    @Test
+    public void testIsConvex() {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        Path path = new Path();
+        path.addRect(0, 0, 100, 100, Path.Direction.CW);
+        while (state.keepRunning()) {
+            path.isConvex();
+        }
+    }
+
+    @Test
+    public void testGetSetFillType() {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        Path path = new Path();
+        path.addRect(0, 0, 100, 100, Path.Direction.CW);
+        while (state.keepRunning()) {
+            path.setFillType(Path.FillType.EVEN_ODD);
+            path.getFillType();
+        }
+    }
+
+    @Test
+    public void testIsRect() {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        Path path = new Path();
+        path.addRect(0, 0, 100, 100, Path.Direction.CW);
+        final RectF outRect = new RectF();
+        while (state.keepRunning()) {
+            path.isRect(outRect);
+        }
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java
index 922a475..dfbabeb 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java
@@ -16,14 +16,18 @@
 
 package android.graphics.perftests;
 
+import android.graphics.Outline;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 import android.support.test.filters.LargeTest;
+import android.view.DisplayListCanvas;
 import android.view.RenderNode;
 
 import org.junit.Rule;
 import org.junit.Test;
 
+import java.util.ArrayList;
+
 @LargeTest
 public class RenderNodePerfTest {
     @Rule
@@ -65,4 +69,58 @@
             node.isValid();
         }
     }
+
+    @Test
+    public void testStartEnd() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        RenderNode node = RenderNode.create("LinearLayout", null);
+        while (state.keepRunning()) {
+            DisplayListCanvas canvas = node.start(100, 100);
+            node.end(canvas);
+        }
+    }
+
+    @Test
+    public void testStartEndDeepHierarchy() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        RenderNode[] nodes = new RenderNode[30];
+        DisplayListCanvas[] canvases = new DisplayListCanvas[nodes.length];
+        for (int i = 0; i < nodes.length; i++) {
+            nodes[i] = RenderNode.create("LinearLayout", null);
+        }
+
+        while (state.keepRunning()) {
+            for (int i = 0; i < nodes.length; i++) {
+                canvases[i] = nodes[i].start(100, 100);
+            }
+            for (int i = nodes.length - 1; i >= 0; i--) {
+                nodes[i].end(canvases[i]);
+            }
+        }
+    }
+
+    @Test
+    public void testHasIdentityMatrix() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        RenderNode node = RenderNode.create("LinearLayout", null);
+        while (state.keepRunning()) {
+            node.hasIdentityMatrix();
+        }
+    }
+
+    @Test
+    public void testSetOutline() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        RenderNode node = RenderNode.create("LinearLayout", null);
+        Outline a = new Outline();
+        a.setRoundRect(0, 0, 100, 100, 10);
+        Outline b = new Outline();
+        b.setRect(50, 50, 150, 150);
+        b.setAlpha(0.5f);
+
+        while (state.keepRunning()) {
+            node.setOutline(a);
+            node.setOutline(b);
+        }
+    }
 }
diff --git a/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java b/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java
index c7da48c..6159da4 100644
--- a/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java
+++ b/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java
@@ -121,7 +121,7 @@
     @Parameterized.Parameters(name = "Factory:{0},depth:{1}")
     public static Iterable<Object[]> params() {
         List<Object[]> params = new ArrayList<>();
-        for (int depth : new int[] {1, 6, 10}) {
+        for (int depth : new int[] { 6 }) {
             for (SubTreeFactory subTreeFactory : sSubTreeFactories) {
                 params.add(new Object[]{ subTreeFactory, depth });
             }
@@ -198,6 +198,21 @@
         });
     }
 
+    @Test
+    public void testRecordAfterAdd() throws Throwable {
+        testParentWithChild((state, width, height, parent, child) -> {
+            while (state.keepRunning()) {
+                state.pauseTiming();
+                parent.removeAllViews();
+                updateAndValidateDisplayList(parent); // Note, done to be safe, likely not needed
+                parent.addView(child);
+                layout(width, height, child);
+                state.resumeTiming();
+
+                updateAndValidateDisplayList(parent);
+            }
+        });
+    }
 
     private void testVisibility(int fromVisibility, int toVisibility) throws Throwable {
         testParentWithChild((state, width, height, parent, child) -> {
diff --git a/api/current.txt b/api/current.txt
index 85aa5df7..89573ac 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -750,6 +750,8 @@
     field public static final int keyWidth = 16843325; // 0x101023d
     field public static final int keyboardLayout = 16843691; // 0x10103ab
     field public static final int keyboardMode = 16843341; // 0x101024d
+    field public static final int keyboardNavigationCluster = 16844096; // 0x1010540
+    field public static final int keyboardNavigationSection = 16844097; // 0x1010541
     field public static final int keycode = 16842949; // 0x10100c5
     field public static final int killAfterRestore = 16843420; // 0x101029c
     field public static final int label = 16842753; // 0x1010001
@@ -893,11 +895,13 @@
     field public static final int negativeButtonText = 16843254; // 0x10101f6
     field public static final int nestedScrollingEnabled = 16843830; // 0x1010436
     field public static final int networkSecurityConfig = 16844071; // 0x1010527
+    field public static final int nextClusterForward = 16844098; // 0x1010542
     field public static final int nextFocusDown = 16842980; // 0x10100e4
     field public static final int nextFocusForward = 16843580; // 0x101033c
     field public static final int nextFocusLeft = 16842977; // 0x10100e1
     field public static final int nextFocusRight = 16842978; // 0x10100e2
     field public static final int nextFocusUp = 16842979; // 0x10100e3
+    field public static final int nextSectionForward = 16844099; // 0x1010543
     field public static final int noHistory = 16843309; // 0x101022d
     field public static final int normalScreens = 16843397; // 0x1010285
     field public static final int notificationTimeout = 16843651; // 0x1010383
@@ -3653,6 +3657,7 @@
     method public void setIntent(android.content.Intent);
     method public final void setMediaController(android.media.session.MediaController);
     method public void setOverlayWithDecorCaptionEnabled(boolean);
+    method public void setPictureInPictureActions(java.util.List<android.app.RemoteAction>);
     method public void setPictureInPictureAspectRatio(float);
     method public final deprecated void setProgress(int);
     method public final deprecated void setProgressBarIndeterminate(boolean);
@@ -3733,6 +3738,7 @@
     method public int getLauncherLargeIconDensity();
     method public int getLauncherLargeIconSize();
     method public int getLockTaskModeState();
+    method public static int getMaxNumPictureInPictureActions();
     method public int getMemoryClass();
     method public void getMemoryInfo(android.app.ActivityManager.MemoryInfo);
     method public static void getMyMemoryState(android.app.ActivityManager.RunningAppProcessInfo);
@@ -5543,6 +5549,22 @@
     field public static final int STYLE_SPINNER = 0; // 0x0
   }
 
+  public final class RemoteAction implements android.os.Parcelable {
+    ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.RemoteAction.OnActionListener);
+    method public android.app.RemoteAction clone();
+    method public int describeContents();
+    method public void dump(java.lang.String, java.io.PrintWriter);
+    method public java.lang.CharSequence getContentDescription();
+    method public android.graphics.drawable.Icon getIcon();
+    method public java.lang.CharSequence getTitle();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.RemoteAction> CREATOR;
+  }
+
+  public static abstract interface RemoteAction.OnActionListener {
+    method public abstract void onAction(android.app.RemoteAction);
+  }
+
   public final class RemoteInput implements android.os.Parcelable {
     method public static void addResultsToIntent(android.app.RemoteInput[], android.content.Intent, android.os.Bundle);
     method public int describeContents();
@@ -6202,6 +6224,9 @@
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
     field public static final deprecated java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM";
+    field public static final java.lang.String EXTRA_PROVISIONING_DISCLAIMERS = "android.app.extra.PROVISIONING_DISCLAIMERS";
+    field public static final java.lang.String EXTRA_PROVISIONING_DISCLAIMER_CONTENT = "android.app.extra.PROVISIONING_DISCLAIMER_CONTENT";
+    field public static final java.lang.String EXTRA_PROVISIONING_DISCLAIMER_HEADER = "android.app.extra.PROVISIONING_DISCLAIMER_HEADER";
     field public static final java.lang.String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.PROVISIONING_EMAIL_ADDRESS";
     field public static final java.lang.String EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION = "android.app.extra.PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION";
     field public static final java.lang.String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
@@ -8385,6 +8410,7 @@
     field public static final java.lang.String TELECOM_SERVICE = "telecom";
     field public static final java.lang.String TELEPHONY_SERVICE = "phone";
     field public static final java.lang.String TELEPHONY_SUBSCRIPTION_SERVICE = "telephony_subscription_service";
+    field public static final java.lang.String TEXT_CLASSIFICATION_SERVICE = "textclassification";
     field public static final java.lang.String TEXT_SERVICES_MANAGER_SERVICE = "textservices";
     field public static final java.lang.String TV_INPUT_SERVICE = "tv_input";
     field public static final java.lang.String UI_MODE_SERVICE = "uimode";
@@ -9690,6 +9716,7 @@
 
   public class LauncherApps {
     method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
+    method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent);
     method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
     method public android.graphics.drawable.Drawable getShortcutIconDrawable(android.content.pm.ShortcutInfo, int);
     method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
@@ -9705,6 +9732,8 @@
     method public void startShortcut(java.lang.String, java.lang.String, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
     method public void startShortcut(android.content.pm.ShortcutInfo, android.graphics.Rect, android.os.Bundle);
     method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
+    field public static final java.lang.String ACTION_CONFIRM_PIN_ITEM = "android.content.pm.action.CONFIRM_PIN_ITEM";
+    field public static final java.lang.String EXTRA_PIN_ITEM_REQUEST = "android.content.pm.extra.PIN_ITEM_REQUEST";
   }
 
   public static abstract class LauncherApps.Callback {
@@ -9719,6 +9748,21 @@
     method public void onShortcutsChanged(java.lang.String, java.util.List<android.content.pm.ShortcutInfo>, android.os.UserHandle);
   }
 
+  public static final class LauncherApps.PinItemRequest implements android.os.Parcelable {
+    method public boolean accept(android.os.Bundle);
+    method public boolean accept();
+    method public int describeContents();
+    method public int getRequestType();
+    method public android.content.pm.ShortcutInfo getShortcutInfo();
+    method public boolean isValid();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.content.pm.LauncherApps.PinItemRequest> CREATOR;
+    field public static final int REQUEST_TYPE_SHORTCUT = 1; // 0x1
+  }
+
+  public static abstract class LauncherApps.PinItemRequest.RequestType implements java.lang.annotation.Annotation {
+  }
+
   public static class LauncherApps.ShortcutQuery {
     ctor public LauncherApps.ShortcutQuery();
     method public android.content.pm.LauncherApps.ShortcutQuery setActivity(android.content.ComponentName);
@@ -10283,9 +10327,11 @@
     method public int getMaxShortcutCountPerActivity();
     method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
     method public boolean isRateLimitingActive();
+    method public boolean isRequestPinShortcutSupported();
     method public void removeAllDynamicShortcuts();
     method public void removeDynamicShortcuts(java.util.List<java.lang.String>);
     method public void reportShortcutUsed(java.lang.String);
+    method public boolean requestPinShortcut(android.content.pm.ShortcutInfo, android.content.IntentSender);
     method public boolean setDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
     method public boolean updateShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
   }
@@ -11723,6 +11769,8 @@
     method public static android.graphics.Bitmap createBitmap(android.graphics.Bitmap, int, int, int, int, android.graphics.Matrix, boolean);
     method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config);
     method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config);
+    method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config, boolean);
+    method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config, boolean);
     method public static android.graphics.Bitmap createBitmap(int[], int, int, int, int, android.graphics.Bitmap.Config);
     method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int[], int, int, int, int, android.graphics.Bitmap.Config);
     method public static android.graphics.Bitmap createBitmap(int[], int, int, android.graphics.Bitmap.Config);
@@ -11786,6 +11834,8 @@
     enum_constant public static final android.graphics.Bitmap.Config ALPHA_8;
     enum_constant public static final deprecated android.graphics.Bitmap.Config ARGB_4444;
     enum_constant public static final android.graphics.Bitmap.Config ARGB_8888;
+    enum_constant public static final android.graphics.Bitmap.Config HARDWARE;
+    enum_constant public static final android.graphics.Bitmap.Config RGBA_F16;
     enum_constant public static final android.graphics.Bitmap.Config RGB_565;
   }
 
@@ -12145,6 +12195,7 @@
     method public android.graphics.Bitmap render();
     method public android.graphics.ColorSpace.Renderer showWhitePoint(boolean);
     method public android.graphics.ColorSpace.Renderer size(int);
+    method public android.graphics.ColorSpace.Renderer uniformChromaticityScale(boolean);
   }
 
   public static class ColorSpace.Rgb extends android.graphics.ColorSpace {
@@ -12246,12 +12297,6 @@
     enum_constant public static final android.graphics.Interpolator.Result NORMAL;
   }
 
-  public deprecated class LayerRasterizer extends android.graphics.Rasterizer {
-    ctor public LayerRasterizer();
-    method public void addLayer(android.graphics.Paint, float, float);
-    method public void addLayer(android.graphics.Paint);
-  }
-
   public class LightingColorFilter extends android.graphics.ColorFilter {
     ctor public LightingColorFilter(int, int);
   }
@@ -12413,7 +12458,6 @@
     method public int getOffsetForAdvance(char[], int, int, int, int, boolean, float);
     method public int getOffsetForAdvance(java.lang.CharSequence, int, int, int, int, boolean, float);
     method public android.graphics.PathEffect getPathEffect();
-    method public deprecated android.graphics.Rasterizer getRasterizer();
     method public float getRunAdvance(char[], int, int, int, int, boolean, int);
     method public float getRunAdvance(java.lang.CharSequence, int, int, int, int, boolean, int);
     method public android.graphics.Shader getShader();
@@ -12470,7 +12514,6 @@
     method public void setLinearText(boolean);
     method public android.graphics.MaskFilter setMaskFilter(android.graphics.MaskFilter);
     method public android.graphics.PathEffect setPathEffect(android.graphics.PathEffect);
-    method public deprecated android.graphics.Rasterizer setRasterizer(android.graphics.Rasterizer);
     method public android.graphics.Shader setShader(android.graphics.Shader);
     method public void setShadowLayer(float, float, float, int);
     method public void setStrikeThruText(boolean);
@@ -12688,7 +12731,9 @@
     field public static final deprecated int RGBA_4444 = 7; // 0x7
     field public static final deprecated int RGBA_5551 = 6; // 0x6
     field public static final int RGBA_8888 = 1; // 0x1
+    field public static final int RGBA_F16 = 22; // 0x16
     field public static final int RGBX_8888 = 2; // 0x2
+    field public static final int RGBX_F16 = 23; // 0x17
     field public static final deprecated int RGB_332 = 11; // 0xb
     field public static final int RGB_565 = 4; // 0x4
     field public static final int RGB_888 = 3; // 0x3
@@ -12777,10 +12822,6 @@
     ctor public RadialGradient(float, float, float, int, int, android.graphics.Shader.TileMode);
   }
 
-  public deprecated class Rasterizer {
-    ctor public Rasterizer();
-  }
-
   public final class Rect implements android.os.Parcelable {
     ctor public Rect();
     ctor public Rect(int, int, int, int);
@@ -15248,6 +15289,10 @@
     field public static final int CONTROL = 1; // 0x1
     field public static final int CR = 2; // 0x2
     field public static final int EXTEND = 3; // 0x3
+    field public static final int E_BASE = 13; // 0xd
+    field public static final int E_BASE_GAZ = 14; // 0xe
+    field public static final int E_MODIFIER = 15; // 0xf
+    field public static final int GLUE_AFTER_ZWJ = 16; // 0x10
     field public static final int L = 4; // 0x4
     field public static final int LF = 5; // 0x5
     field public static final int LV = 6; // 0x6
@@ -15258,6 +15303,7 @@
     field public static final int SPACING_MARK = 10; // 0xa
     field public static final int T = 8; // 0x8
     field public static final int V = 9; // 0x9
+    field public static final int ZWJ = 17; // 0x11
   }
 
   public static abstract interface UCharacter.HangulSyllableType {
@@ -15270,6 +15316,9 @@
   }
 
   public static abstract interface UCharacter.JoiningGroup {
+    field public static final int AFRICAN_FEH = 86; // 0x56
+    field public static final int AFRICAN_NOON = 87; // 0x57
+    field public static final int AFRICAN_QAF = 88; // 0x58
     field public static final int AIN = 1; // 0x1
     field public static final int ALAPH = 2; // 0x2
     field public static final int ALEF = 3; // 0x3
@@ -15383,6 +15432,8 @@
     field public static final int CONDITIONAL_JAPANESE_STARTER = 37; // 0x25
     field public static final int CONTINGENT_BREAK = 7; // 0x7
     field public static final int EXCLAMATION = 11; // 0xb
+    field public static final int E_BASE = 40; // 0x28
+    field public static final int E_MODIFIER = 41; // 0x29
     field public static final int GLUE = 12; // 0xc
     field public static final int H2 = 31; // 0x1f
     field public static final int H3 = 32; // 0x20
@@ -15409,6 +15460,7 @@
     field public static final int SURROGATE = 25; // 0x19
     field public static final int UNKNOWN = 0; // 0x0
     field public static final int WORD_JOINER = 30; // 0x1e
+    field public static final int ZWJ = 42; // 0x2a
     field public static final int ZWSPACE = 28; // 0x1c
   }
 
@@ -15442,6 +15494,8 @@
     method public int getID();
     method public static android.icu.lang.UCharacter.UnicodeBlock getInstance(int);
     method public static android.icu.lang.UCharacter.UnicodeBlock of(int);
+    field public static final android.icu.lang.UCharacter.UnicodeBlock ADLAM;
+    field public static final int ADLAM_ID = 263; // 0x107
     field public static final android.icu.lang.UCharacter.UnicodeBlock AEGEAN_NUMBERS;
     field public static final int AEGEAN_NUMBERS_ID = 119; // 0x77
     field public static final android.icu.lang.UCharacter.UnicodeBlock AHOM;
@@ -15490,6 +15544,8 @@
     field public static final int BATAK_ID = 199; // 0xc7
     field public static final android.icu.lang.UCharacter.UnicodeBlock BENGALI;
     field public static final int BENGALI_ID = 16; // 0x10
+    field public static final android.icu.lang.UCharacter.UnicodeBlock BHAIKSUKI;
+    field public static final int BHAIKSUKI_ID = 264; // 0x108
     field public static final android.icu.lang.UCharacter.UnicodeBlock BLOCK_ELEMENTS;
     field public static final int BLOCK_ELEMENTS_ID = 53; // 0x35
     field public static final android.icu.lang.UCharacter.UnicodeBlock BOPOMOFO;
@@ -15579,6 +15635,8 @@
     field public static final int CYRILLIC_EXTENDED_A_ID = 158; // 0x9e
     field public static final android.icu.lang.UCharacter.UnicodeBlock CYRILLIC_EXTENDED_B;
     field public static final int CYRILLIC_EXTENDED_B_ID = 160; // 0xa0
+    field public static final android.icu.lang.UCharacter.UnicodeBlock CYRILLIC_EXTENDED_C;
+    field public static final int CYRILLIC_EXTENDED_C_ID = 265; // 0x109
     field public static final int CYRILLIC_ID = 9; // 0x9
     field public static final android.icu.lang.UCharacter.UnicodeBlock CYRILLIC_SUPPLEMENT;
     field public static final android.icu.lang.UCharacter.UnicodeBlock CYRILLIC_SUPPLEMENTARY;
@@ -15632,6 +15690,8 @@
     field public static final int GEORGIAN_SUPPLEMENT_ID = 135; // 0x87
     field public static final android.icu.lang.UCharacter.UnicodeBlock GLAGOLITIC;
     field public static final int GLAGOLITIC_ID = 136; // 0x88
+    field public static final android.icu.lang.UCharacter.UnicodeBlock GLAGOLITIC_SUPPLEMENT;
+    field public static final int GLAGOLITIC_SUPPLEMENT_ID = 266; // 0x10a
     field public static final android.icu.lang.UCharacter.UnicodeBlock GOTHIC;
     field public static final int GOTHIC_ID = 89; // 0x59
     field public static final android.icu.lang.UCharacter.UnicodeBlock GRANTHA;
@@ -15670,6 +15730,8 @@
     field public static final int HIRAGANA_ID = 62; // 0x3e
     field public static final android.icu.lang.UCharacter.UnicodeBlock IDEOGRAPHIC_DESCRIPTION_CHARACTERS;
     field public static final int IDEOGRAPHIC_DESCRIPTION_CHARACTERS_ID = 60; // 0x3c
+    field public static final android.icu.lang.UCharacter.UnicodeBlock IDEOGRAPHIC_SYMBOLS_AND_PUNCTUATION;
+    field public static final int IDEOGRAPHIC_SYMBOLS_AND_PUNCTUATION_ID = 267; // 0x10b
     field public static final android.icu.lang.UCharacter.UnicodeBlock IMPERIAL_ARAMAIC;
     field public static final int IMPERIAL_ARAMAIC_ID = 186; // 0xba
     field public static final android.icu.lang.UCharacter.UnicodeBlock INSCRIPTIONAL_PAHLAVI;
@@ -15754,6 +15816,8 @@
     field public static final int MANDAIC_ID = 198; // 0xc6
     field public static final android.icu.lang.UCharacter.UnicodeBlock MANICHAEAN;
     field public static final int MANICHAEAN_ID = 234; // 0xea
+    field public static final android.icu.lang.UCharacter.UnicodeBlock MARCHEN;
+    field public static final int MARCHEN_ID = 268; // 0x10c
     field public static final android.icu.lang.UCharacter.UnicodeBlock MATHEMATICAL_ALPHANUMERIC_SYMBOLS;
     field public static final int MATHEMATICAL_ALPHANUMERIC_SYMBOLS_ID = 93; // 0x5d
     field public static final android.icu.lang.UCharacter.UnicodeBlock MATHEMATICAL_OPERATORS;
@@ -15788,6 +15852,8 @@
     field public static final int MODI_ID = 236; // 0xec
     field public static final android.icu.lang.UCharacter.UnicodeBlock MONGOLIAN;
     field public static final int MONGOLIAN_ID = 37; // 0x25
+    field public static final android.icu.lang.UCharacter.UnicodeBlock MONGOLIAN_SUPPLEMENT;
+    field public static final int MONGOLIAN_SUPPLEMENT_ID = 269; // 0x10d
     field public static final android.icu.lang.UCharacter.UnicodeBlock MRO;
     field public static final int MRO_ID = 237; // 0xed
     field public static final android.icu.lang.UCharacter.UnicodeBlock MULTANI;
@@ -15802,6 +15868,8 @@
     field public static final int MYANMAR_ID = 28; // 0x1c
     field public static final android.icu.lang.UCharacter.UnicodeBlock NABATAEAN;
     field public static final int NABATAEAN_ID = 239; // 0xef
+    field public static final android.icu.lang.UCharacter.UnicodeBlock NEWA;
+    field public static final int NEWA_ID = 270; // 0x10e
     field public static final android.icu.lang.UCharacter.UnicodeBlock NEW_TAI_LUE;
     field public static final int NEW_TAI_LUE_ID = 139; // 0x8b
     field public static final android.icu.lang.UCharacter.UnicodeBlock NKO;
@@ -15833,6 +15901,8 @@
     field public static final int ORIYA_ID = 19; // 0x13
     field public static final android.icu.lang.UCharacter.UnicodeBlock ORNAMENTAL_DINGBATS;
     field public static final int ORNAMENTAL_DINGBATS_ID = 242; // 0xf2
+    field public static final android.icu.lang.UCharacter.UnicodeBlock OSAGE;
+    field public static final int OSAGE_ID = 271; // 0x10f
     field public static final android.icu.lang.UCharacter.UnicodeBlock OSMANYA;
     field public static final int OSMANYA_ID = 122; // 0x7a
     field public static final android.icu.lang.UCharacter.UnicodeBlock PAHAWH_HMONG;
@@ -15935,6 +16005,10 @@
     field public static final int TAKRI_ID = 220; // 0xdc
     field public static final android.icu.lang.UCharacter.UnicodeBlock TAMIL;
     field public static final int TAMIL_ID = 20; // 0x14
+    field public static final android.icu.lang.UCharacter.UnicodeBlock TANGUT;
+    field public static final android.icu.lang.UCharacter.UnicodeBlock TANGUT_COMPONENTS;
+    field public static final int TANGUT_COMPONENTS_ID = 273; // 0x111
+    field public static final int TANGUT_ID = 272; // 0x110
     field public static final android.icu.lang.UCharacter.UnicodeBlock TELUGU;
     field public static final int TELUGU_ID = 21; // 0x15
     field public static final android.icu.lang.UCharacter.UnicodeBlock THAANA;
@@ -15981,7 +16055,11 @@
     field public static final int DOUBLE_QUOTE = 16; // 0x10
     field public static final int EXTEND = 9; // 0x9
     field public static final int EXTENDNUMLET = 7; // 0x7
+    field public static final int E_BASE = 17; // 0x11
+    field public static final int E_BASE_GAZ = 18; // 0x12
+    field public static final int E_MODIFIER = 19; // 0x13
     field public static final int FORMAT = 2; // 0x2
+    field public static final int GLUE_AFTER_ZWJ = 20; // 0x14
     field public static final int HEBREW_LETTER = 14; // 0xe
     field public static final int KATAKANA = 3; // 0x3
     field public static final int LF = 10; // 0xa
@@ -15993,6 +16071,7 @@
     field public static final int OTHER = 0; // 0x0
     field public static final int REGIONAL_INDICATOR = 13; // 0xd
     field public static final int SINGLE_QUOTE = 15; // 0xf
+    field public static final int ZWJ = 21; // 0x15
   }
 
   public final class UCharacterCategory implements android.icu.lang.UCharacterEnums.ECharacterCategory {
@@ -16211,6 +16290,7 @@
     method public static final boolean hasScript(int, int);
     method public static final boolean isCased(int);
     method public static final boolean isRightToLeft(int);
+    field public static final int ADLAM = 167; // 0xa7
     field public static final int AFAKA = 147; // 0x93
     field public static final int AHOM = 161; // 0xa1
     field public static final int ANATOLIAN_HIEROGLYPHS = 156; // 0x9c
@@ -16222,6 +16302,7 @@
     field public static final int BASSA_VAH = 134; // 0x86
     field public static final int BATAK = 63; // 0x3f
     field public static final int BENGALI = 4; // 0x4
+    field public static final int BHAIKSUKI = 168; // 0xa8
     field public static final int BLISSYMBOLS = 64; // 0x40
     field public static final int BOOK_PAHLAVI = 124; // 0x7c
     field public static final int BOPOMOFO = 5; // 0x5
@@ -16260,6 +16341,7 @@
     field public static final int HAN = 17; // 0x11
     field public static final int HANGUL = 18; // 0x12
     field public static final int HANUNOO = 43; // 0x2b
+    field public static final int HAN_WITH_BOPOMOFO = 172; // 0xac
     field public static final int HARAPPAN_INDUS = 77; // 0x4d
     field public static final int HATRAN = 162; // 0xa2
     field public static final int HEBREW = 19; // 0x13
@@ -16270,6 +16352,7 @@
     field public static final int INSCRIPTIONAL_PAHLAVI = 122; // 0x7a
     field public static final int INSCRIPTIONAL_PARTHIAN = 125; // 0x7d
     field public static final int INVALID_CODE = -1; // 0xffffffff
+    field public static final int JAMO = 173; // 0xad
     field public static final int JAPANESE = 105; // 0x69
     field public static final int JAVANESE = 78; // 0x4e
     field public static final int JURCHEN = 148; // 0x94
@@ -16303,6 +16386,7 @@
     field public static final int MANDAEAN = 84; // 0x54
     field public static final int MANDAIC = 84; // 0x54
     field public static final int MANICHAEAN = 121; // 0x79
+    field public static final int MARCHEN = 169; // 0xa9
     field public static final int MATHEMATICAL_NOTATION = 128; // 0x80
     field public static final int MAYAN_HIEROGLYPHS = 85; // 0x55
     field public static final int MEITEI_MAYEK = 115; // 0x73
@@ -16319,6 +16403,7 @@
     field public static final int MYANMAR = 28; // 0x1c
     field public static final int NABATAEAN = 143; // 0x8f
     field public static final int NAKHI_GEBA = 132; // 0x84
+    field public static final int NEWA = 170; // 0xaa
     field public static final int NEW_TAI_LUE = 59; // 0x3b
     field public static final int NKO = 87; // 0x57
     field public static final int NUSHU = 150; // 0x96
@@ -16333,6 +16418,7 @@
     field public static final int OL_CHIKI = 109; // 0x6d
     field public static final int ORIYA = 31; // 0x1f
     field public static final int ORKHON = 88; // 0x58
+    field public static final int OSAGE = 171; // 0xab
     field public static final int OSMANYA = 50; // 0x32
     field public static final int PAHAWH_HMONG = 75; // 0x4b
     field public static final int PALMYRENE = 144; // 0x90
@@ -16358,6 +16444,7 @@
     field public static final int SUNDANESE = 113; // 0x71
     field public static final int SYLOTI_NAGRI = 58; // 0x3a
     field public static final int SYMBOLS = 129; // 0x81
+    field public static final int SYMBOLS_EMOJI = 174; // 0xae
     field public static final int SYRIAC = 34; // 0x22
     field public static final int TAGALOG = 42; // 0x2a
     field public static final int TAGBANWA = 45; // 0x2d
@@ -16884,6 +16971,8 @@
     method public static final android.icu.text.DateFormat.BooleanAttribute[] values();
     enum_constant public static final android.icu.text.DateFormat.BooleanAttribute PARSE_ALLOW_NUMERIC;
     enum_constant public static final android.icu.text.DateFormat.BooleanAttribute PARSE_ALLOW_WHITESPACE;
+    enum_constant public static final android.icu.text.DateFormat.BooleanAttribute PARSE_MULTIPLE_PATTERNS_FOR_MATCH;
+    enum_constant public static final android.icu.text.DateFormat.BooleanAttribute PARSE_PARTIAL_LITERAL_MATCH;
   }
 
   public static class DateFormat.Field extends java.text.Format.Field {
@@ -17568,6 +17657,7 @@
     field public static final int PERCENTSTYLE = 2; // 0x2
     field public static final int PLURALCURRENCYSTYLE = 6; // 0x6
     field public static final int SCIENTIFICSTYLE = 3; // 0x3
+    field public static final int STANDARDCURRENCYSTYLE = 9; // 0x9
   }
 
   public static class NumberFormat.Field extends java.text.Format.Field {
@@ -18362,7 +18452,7 @@
     field public static final int AM_PM = 9; // 0x9
     field public static final int APRIL = 3; // 0x3
     field public static final int AUGUST = 7; // 0x7
-    field protected static final int BASE_FIELD_COUNT = 23; // 0x17
+    field protected static final deprecated int BASE_FIELD_COUNT = 23; // 0x17
     field public static final int DATE = 5; // 0x5
     field public static final int DAY_OF_MONTH = 5; // 0x5
     field public static final int DAY_OF_WEEK = 7; // 0x7
@@ -18390,7 +18480,7 @@
     field public static final int MARCH = 2; // 0x2
     field protected static final int MAXIMUM = 3; // 0x3
     field protected static final java.util.Date MAX_DATE;
-    field protected static final int MAX_FIELD_COUNT = 32; // 0x20
+    field protected static final deprecated int MAX_FIELD_COUNT = 32; // 0x20
     field protected static final int MAX_JULIAN = 2130706432; // 0x7f000000
     field protected static final long MAX_MILLIS = 183882168921600000L; // 0x28d47dbbf19b000L
     field public static final int MAY = 4; // 0x4
@@ -18710,6 +18800,7 @@
     field public static final android.icu.util.MeasureUnit CELSIUS;
     field public static final android.icu.util.MeasureUnit CENTILITER;
     field public static final android.icu.util.MeasureUnit CENTIMETER;
+    field public static final android.icu.util.MeasureUnit CENTURY;
     field public static final android.icu.util.MeasureUnit CUBIC_CENTIMETER;
     field public static final android.icu.util.MeasureUnit CUBIC_FOOT;
     field public static final android.icu.util.MeasureUnit CUBIC_INCH;
@@ -18718,6 +18809,7 @@
     field public static final android.icu.util.MeasureUnit CUBIC_MILE;
     field public static final android.icu.util.MeasureUnit CUBIC_YARD;
     field public static final android.icu.util.MeasureUnit CUP;
+    field public static final android.icu.util.MeasureUnit CUP_METRIC;
     field public static final android.icu.util.TimeUnit DAY;
     field public static final android.icu.util.MeasureUnit DECILITER;
     field public static final android.icu.util.MeasureUnit DECIMETER;
@@ -18729,6 +18821,7 @@
     field public static final android.icu.util.MeasureUnit FOOT;
     field public static final android.icu.util.MeasureUnit FURLONG;
     field public static final android.icu.util.MeasureUnit GALLON;
+    field public static final android.icu.util.MeasureUnit GENERIC_TEMPERATURE;
     field public static final android.icu.util.MeasureUnit GIGABIT;
     field public static final android.icu.util.MeasureUnit GIGABYTE;
     field public static final android.icu.util.MeasureUnit GIGAHERTZ;
@@ -18756,8 +18849,10 @@
     field public static final android.icu.util.MeasureUnit KILOMETER_PER_HOUR;
     field public static final android.icu.util.MeasureUnit KILOWATT;
     field public static final android.icu.util.MeasureUnit KILOWATT_HOUR;
+    field public static final android.icu.util.MeasureUnit KNOT;
     field public static final android.icu.util.MeasureUnit LIGHT_YEAR;
     field public static final android.icu.util.MeasureUnit LITER;
+    field public static final android.icu.util.MeasureUnit LITER_PER_100KILOMETERS;
     field public static final android.icu.util.MeasureUnit LITER_PER_KILOMETER;
     field public static final android.icu.util.MeasureUnit LUX;
     field public static final android.icu.util.MeasureUnit MEGABIT;
@@ -18775,6 +18870,7 @@
     field public static final android.icu.util.MeasureUnit MILE;
     field public static final android.icu.util.MeasureUnit MILE_PER_GALLON;
     field public static final android.icu.util.MeasureUnit MILE_PER_HOUR;
+    field public static final android.icu.util.MeasureUnit MILE_SCANDINAVIAN;
     field public static final android.icu.util.MeasureUnit MILLIAMPERE;
     field public static final android.icu.util.MeasureUnit MILLIBAR;
     field public static final android.icu.util.MeasureUnit MILLIGRAM;
@@ -18794,10 +18890,12 @@
     field public static final android.icu.util.MeasureUnit PARSEC;
     field public static final android.icu.util.MeasureUnit PICOMETER;
     field public static final android.icu.util.MeasureUnit PINT;
+    field public static final android.icu.util.MeasureUnit PINT_METRIC;
     field public static final android.icu.util.MeasureUnit POUND;
     field public static final android.icu.util.MeasureUnit POUND_PER_SQUARE_INCH;
     field public static final android.icu.util.MeasureUnit QUART;
     field public static final android.icu.util.MeasureUnit RADIAN;
+    field public static final android.icu.util.MeasureUnit REVOLUTION_ANGLE;
     field public static final android.icu.util.TimeUnit SECOND;
     field public static final android.icu.util.MeasureUnit SQUARE_CENTIMETER;
     field public static final android.icu.util.MeasureUnit SQUARE_FOOT;
@@ -19109,6 +19207,7 @@
     field public static final android.icu.util.VersionInfo UNICODE_6_3;
     field public static final android.icu.util.VersionInfo UNICODE_7_0;
     field public static final android.icu.util.VersionInfo UNICODE_8_0;
+    field public static final android.icu.util.VersionInfo UNICODE_9_0;
   }
 
 }
@@ -22615,6 +22714,7 @@
     method public android.content.ComponentName getServiceComponent();
     method public android.media.session.MediaSession.Token getSessionToken();
     method public boolean isConnected();
+    method public void search(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SearchCallback);
     method public void subscribe(java.lang.String, android.media.browse.MediaBrowser.SubscriptionCallback);
     method public void subscribe(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SubscriptionCallback);
     method public void unsubscribe(java.lang.String);
@@ -22650,6 +22750,12 @@
     field public static final int FLAG_PLAYABLE = 2; // 0x2
   }
 
+  public static abstract class MediaBrowser.SearchCallback {
+    ctor public MediaBrowser.SearchCallback();
+    method public void onError(java.lang.String, android.os.Bundle);
+    method public void onSearchResult(java.lang.String, android.os.Bundle, java.util.List<android.media.browse.MediaBrowser.MediaItem>);
+  }
+
   public static abstract class MediaBrowser.SubscriptionCallback {
     ctor public MediaBrowser.SubscriptionCallback();
     method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>);
@@ -29720,6 +29826,7 @@
     method public deprecated void setUserRestrictions(android.os.Bundle, android.os.UserHandle);
     method public static boolean supportsMultipleUsers();
     field public static final java.lang.String ALLOW_PARENT_PROFILE_APP_LINKING = "allow_parent_profile_app_linking";
+    field public static final java.lang.String DISALLOW_ADD_MANAGED_PROFILE = "no_add_managed_profile";
     field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user";
     field public static final java.lang.String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
     field public static final java.lang.String DISALLOW_APPS_CONTROL = "no_control_apps";
@@ -29744,6 +29851,7 @@
     field public static final java.lang.String DISALLOW_NETWORK_RESET = "no_network_reset";
     field public static final java.lang.String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam";
     field public static final java.lang.String DISALLOW_OUTGOING_CALLS = "no_outgoing_calls";
+    field public static final java.lang.String DISALLOW_REMOVE_MANAGED_PROFILE = "no_remove_managed_profile";
     field public static final java.lang.String DISALLOW_REMOVE_USER = "no_remove_user";
     field public static final java.lang.String DISALLOW_SAFE_BOOT = "no_safe_boot";
     field public static final java.lang.String DISALLOW_SET_USER_ICON = "no_set_user_icon";
@@ -34876,7 +34984,8 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConnected();
     method public void onDisconnected();
-    method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.CancellationSignal, android.service.autofill.FillCallback);
+    method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback);
+    method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.SaveCallback);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
   }
 
@@ -34894,6 +35003,11 @@
     method public android.service.autofill.FillCallback.FillData.Builder setTextField(int, java.lang.String);
   }
 
+  public final class SaveCallback {
+    method public void onFailure(java.lang.CharSequence);
+    method public void onSuccess(int[]);
+  }
+
 }
 
 package android.service.carrier {
@@ -35075,6 +35189,7 @@
     method public abstract void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>);
     method public void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>, android.os.Bundle);
     method public void onLoadItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>);
+    method public void onSearch(java.lang.String, android.os.Bundle, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>);
     method public void setSessionToken(android.media.session.MediaSession.Token);
     field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
   }
@@ -35164,8 +35279,12 @@
     ctor public NotificationAssistantService();
     method public final void adjustNotification(android.service.notification.Adjustment);
     method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>);
+    method public void createNotificationChannel(java.lang.String, android.app.NotificationChannel);
+    method public void deleteNotificationChannel(java.lang.String, java.lang.String);
+    method public java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String);
     method public final android.os.IBinder onBind(android.content.Intent);
     method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+    method public void updateNotificationChannel(java.lang.String, android.app.NotificationChannel);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
   }
 
@@ -37364,6 +37483,7 @@
     field public static final java.lang.String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
     field public static final java.lang.String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
     field public static final java.lang.String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool";
+    field public static final java.lang.String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
     field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
     field public static final java.lang.String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
     field public static final java.lang.String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
@@ -37901,6 +38021,7 @@
     method public java.lang.String getSimOperatorName();
     method public java.lang.String getSimSerialNumber();
     method public int getSimState();
+    method public int getSimState(int);
     method public java.lang.String getSubscriberId();
     method public java.lang.String getVoiceMailAlphaTag();
     method public java.lang.String getVoiceMailNumber();
@@ -37985,7 +38106,11 @@
     field public static final int PHONE_TYPE_NONE = 0; // 0x0
     field public static final int PHONE_TYPE_SIP = 3; // 0x3
     field public static final int SIM_STATE_ABSENT = 1; // 0x1
+    field public static final int SIM_STATE_CARD_IO_ERROR = 8; // 0x8
+    field public static final int SIM_STATE_CARD_RESTRICTED = 9; // 0x9
     field public static final int SIM_STATE_NETWORK_LOCKED = 4; // 0x4
+    field public static final int SIM_STATE_NOT_READY = 6; // 0x6
+    field public static final int SIM_STATE_PERM_DISABLED = 7; // 0x7
     field public static final int SIM_STATE_PIN_REQUIRED = 2; // 0x2
     field public static final int SIM_STATE_PUK_REQUIRED = 3; // 0x3
     field public static final int SIM_STATE_READY = 5; // 0x5
@@ -38750,7 +38875,7 @@
     method public java.lang.CharSequence subSequence(int, int);
   }
 
-  public class AndroidCharacter {
+  public deprecated class AndroidCharacter {
     ctor public AndroidCharacter();
     method public static void getDirectionalities(char[], byte[], int);
     method public static int getEastAsianWidth(char);
@@ -39244,6 +39369,12 @@
     method public java.util.Map<java.lang.String, java.lang.Float> getTypeConfidence();
   }
 
+  public final class TextClassificationManager implements android.text.TextAssistant {
+    method public void addLinks(android.text.Spannable, int);
+    method public java.util.List<android.text.TextLanguage> detectLanguages(java.lang.CharSequence);
+    method public android.text.TextSelection suggestSelection(java.lang.CharSequence, int, int);
+  }
+
   public abstract interface TextDirectionHeuristic {
     method public abstract boolean isRtl(char[], int, int);
     method public abstract boolean isRtl(java.lang.CharSequence, int, int);
@@ -39259,6 +39390,13 @@
     field public static final android.text.TextDirectionHeuristic RTL;
   }
 
+  public final class TextLanguage {
+    ctor public TextLanguage(int, int, java.util.Map<java.lang.String, java.lang.Float>);
+    method public int getEndIndex();
+    method public java.util.Map<java.lang.String, java.lang.Float> getLanguageConfidence();
+    method public int getStartIndex();
+  }
+
   public class TextPaint extends android.graphics.Paint {
     ctor public TextPaint();
     ctor public TextPaint(int);
@@ -39953,12 +40091,6 @@
     method public void writeToParcel(android.os.Parcel, int);
   }
 
-  public class RasterizerSpan extends android.text.style.CharacterStyle implements android.text.style.UpdateAppearance {
-    ctor public RasterizerSpan(android.graphics.Rasterizer);
-    method public android.graphics.Rasterizer getRasterizer();
-    method public void updateDrawState(android.text.TextPaint);
-  }
-
   public class RelativeSizeSpan extends android.text.style.MetricAffectingSpan implements android.text.ParcelableSpan {
     ctor public RelativeSizeSpan(float);
     ctor public RelativeSizeSpan(android.os.Parcel);
@@ -41606,6 +41738,7 @@
     method public android.view.View findNearestTouchable(android.view.ViewGroup, int, int, int, int[]);
     method public final android.view.View findNextFocus(android.view.ViewGroup, android.view.View, int);
     method public android.view.View findNextFocusFromRect(android.view.ViewGroup, android.graphics.Rect, int);
+    method public android.view.View findNextKeyboardNavigationCluster(android.view.ViewGroup, android.view.View, int);
     method public static android.view.FocusFinder getInstance();
   }
 
@@ -42898,6 +43031,7 @@
     method public void addChildrenForAccessibility(java.util.ArrayList<android.view.View>);
     method public void addFocusables(java.util.ArrayList<android.view.View>, int);
     method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
+    method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
     method public void addOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
     method public void addOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
     method public void addTouchables(java.util.ArrayList<android.view.View>);
@@ -42954,7 +43088,8 @@
     method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
     method public boolean dispatchNestedScroll(int, int, int, int, int[]);
     method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public void dispatchProvideStructure(android.view.ViewStructure);
+    method public deprecated void dispatchProvideStructure(android.view.ViewStructure);
+    method public void dispatchProvideStructure(android.view.ViewStructure, int);
     method protected void dispatchRestoreInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSaveInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSetActivated(boolean);
@@ -43051,11 +43186,13 @@
     method public final int getMeasuredWidthAndState();
     method public int getMinimumHeight();
     method public int getMinimumWidth();
+    method public int getNextClusterForwardId();
     method public int getNextFocusDownId();
     method public int getNextFocusForwardId();
     method public int getNextFocusLeftId();
     method public int getNextFocusRightId();
     method public int getNextFocusUpId();
+    method public int getNextSectionForwardId();
     method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
     method public android.view.ViewOutlineProvider getOutlineProvider();
     method public int getOverScrollMode();
@@ -43158,6 +43295,8 @@
     method public boolean isInEditMode();
     method public boolean isInLayout();
     method public boolean isInTouchMode();
+    method public final boolean isKeyboardNavigationCluster();
+    method public final boolean isKeyboardNavigationSection();
     method public boolean isLaidOut();
     method public boolean isLayoutDirectionResolved();
     method public boolean isLayoutRequested();
@@ -43180,6 +43319,7 @@
     method public boolean isVerticalFadingEdgeEnabled();
     method public boolean isVerticalScrollBarEnabled();
     method public void jumpDrawablesToCurrentState();
+    method public android.view.View keyboardNavigationClusterSearch(int);
     method public void layout(int, int, int, int);
     method public final void measure(int, int);
     method protected static int[] mergeDrawableStates(int[], int[]);
@@ -43220,8 +43360,10 @@
     method protected void onMeasure(int, int);
     method protected void onOverScrolled(int, int, boolean, boolean);
     method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public void onProvideStructure(android.view.ViewStructure);
-    method public void onProvideVirtualStructure(android.view.ViewStructure);
+    method public deprecated void onProvideStructure(android.view.ViewStructure);
+    method public void onProvideStructure(android.view.ViewStructure, int);
+    method public deprecated void onProvideVirtualStructure(android.view.ViewStructure);
+    method public void onProvideVirtualStructure(android.view.ViewStructure, int);
     method public android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int);
     method protected void onRestoreInstanceState(android.os.Parcelable);
     method public void onRtlPropertiesChanged(int);
@@ -43324,6 +43466,8 @@
     method public void setId(int);
     method public void setImportantForAccessibility(int);
     method public void setKeepScreenOn(boolean);
+    method public void setKeyboardNavigationCluster(boolean);
+    method public void setKeyboardNavigationSection(boolean);
     method public void setLabelFor(int);
     method public void setLayerPaint(android.graphics.Paint);
     method public void setLayerType(int, android.graphics.Paint);
@@ -43335,11 +43479,13 @@
     method public void setMinimumHeight(int);
     method public void setMinimumWidth(int);
     method public void setNestedScrollingEnabled(boolean);
+    method public void setNextClusterForwardId(int);
     method public void setNextFocusDownId(int);
     method public void setNextFocusForwardId(int);
     method public void setNextFocusLeftId(int);
     method public void setNextFocusRightId(int);
     method public void setNextFocusUpId(int);
+    method public void setNextSectionForwardId(int);
     method public void setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener);
     method public void setOnClickListener(android.view.View.OnClickListener);
     method public void setOnContextClickListener(android.view.View.OnContextClickListener);
@@ -43423,6 +43569,8 @@
     field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
     field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
     field public static final android.util.Property<android.view.View, java.lang.Float> ALPHA;
+    field public static final int ASSIST_FLAG_NON_SANITIZED_TEXT = 2; // 0x2
+    field public static final int ASSIST_FLAG_SANITIZED_TEXT = 1; // 0x1
     field public static final int DRAG_FLAG_GLOBAL = 256; // 0x100
     field public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 64; // 0x40
     field public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 128; // 0x80
@@ -43819,6 +43967,7 @@
     method protected deprecated boolean isChildrenDrawnWithCacheEnabled();
     method public boolean isMotionEventSplittingEnabled();
     method public boolean isTransitionGroup();
+    method public android.view.View keyboardNavigationClusterSearch(android.view.View, int);
     method public final void layout(int, int, int, int);
     method protected void measureChild(android.view.View, int, int);
     method protected void measureChildWithMargins(android.view.View, int, int, int, int);
@@ -43981,6 +44130,7 @@
     method public abstract boolean isLayoutRequested();
     method public abstract boolean isTextAlignmentResolved();
     method public abstract boolean isTextDirectionResolved();
+    method public abstract android.view.View keyboardNavigationClusterSearch(android.view.View, int);
     method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
     method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
     method public abstract boolean onNestedPreFling(android.view.View, float, float);
@@ -59883,6 +60033,10 @@
     ctor public Locale(java.lang.String, java.lang.String);
     ctor public Locale(java.lang.String);
     method public java.lang.Object clone();
+    method public static java.util.List<java.util.Locale> filter(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.util.Locale>, java.util.Locale.FilteringMode);
+    method public static java.util.List<java.util.Locale> filter(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.util.Locale>);
+    method public static java.util.List<java.lang.String> filterTags(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.lang.String>, java.util.Locale.FilteringMode);
+    method public static java.util.List<java.lang.String> filterTags(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.lang.String>);
     method public static java.util.Locale forLanguageTag(java.lang.String);
     method public static java.util.Locale[] getAvailableLocales();
     method public java.lang.String getCountry();
@@ -59911,6 +60065,8 @@
     method public java.lang.String getUnicodeLocaleType(java.lang.String);
     method public java.lang.String getVariant();
     method public boolean hasExtensions();
+    method public static java.util.Locale lookup(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.util.Locale>);
+    method public static java.lang.String lookupTag(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.lang.String>);
     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();
@@ -59966,6 +60122,28 @@
     enum_constant public static final java.util.Locale.Category FORMAT;
   }
 
+  public static final class Locale.FilteringMode extends java.lang.Enum {
+    method public static java.util.Locale.FilteringMode valueOf(java.lang.String);
+    method public static final java.util.Locale.FilteringMode[] values();
+    enum_constant public static final java.util.Locale.FilteringMode AUTOSELECT_FILTERING;
+    enum_constant public static final java.util.Locale.FilteringMode EXTENDED_FILTERING;
+    enum_constant public static final java.util.Locale.FilteringMode IGNORE_EXTENDED_RANGES;
+    enum_constant public static final java.util.Locale.FilteringMode MAP_EXTENDED_RANGES;
+    enum_constant public static final java.util.Locale.FilteringMode REJECT_EXTENDED_RANGES;
+  }
+
+  public static final class Locale.LanguageRange {
+    ctor public Locale.LanguageRange(java.lang.String);
+    ctor public Locale.LanguageRange(java.lang.String, double);
+    method public java.lang.String getRange();
+    method public double getWeight();
+    method public static java.util.List<java.util.Locale.LanguageRange> mapEquivalents(java.util.List<java.util.Locale.LanguageRange>, java.util.Map<java.lang.String, java.util.List<java.lang.String>>);
+    method public static java.util.List<java.util.Locale.LanguageRange> parse(java.lang.String);
+    method public static java.util.List<java.util.Locale.LanguageRange> parse(java.lang.String, java.util.Map<java.lang.String, java.util.List<java.lang.String>>);
+    field public static final double MAX_WEIGHT = 1.0;
+    field public static final double MIN_WEIGHT = 0.0;
+  }
+
   public class LongSummaryStatistics implements java.util.function.IntConsumer java.util.function.LongConsumer {
     ctor public LongSummaryStatistics();
     method public void accept(int);
@@ -61249,31 +61427,31 @@
     ctor public CopyOnWriteArrayList();
     ctor public CopyOnWriteArrayList(java.util.Collection<? extends E>);
     ctor public CopyOnWriteArrayList(E[]);
-    method public synchronized boolean add(E);
-    method public synchronized void add(int, E);
-    method public synchronized boolean addAll(java.util.Collection<? extends E>);
-    method public synchronized boolean addAll(int, java.util.Collection<? extends E>);
-    method public synchronized int addAllAbsent(java.util.Collection<? extends E>);
-    method public synchronized boolean addIfAbsent(E);
-    method public synchronized void clear();
+    method public boolean add(E);
+    method public void add(int, E);
+    method public boolean addAll(java.util.Collection<? extends E>);
+    method public boolean addAll(int, java.util.Collection<? extends E>);
+    method public int addAllAbsent(java.util.Collection<? extends E>);
+    method public boolean addIfAbsent(E);
+    method public void clear();
     method public java.lang.Object clone();
     method public boolean contains(java.lang.Object);
     method public boolean containsAll(java.util.Collection<?>);
     method public void forEach(java.util.function.Consumer<? super E>);
     method public E get(int);
-    method public int indexOf(E, int);
     method public int indexOf(java.lang.Object);
+    method public int indexOf(E, int);
     method public boolean isEmpty();
     method public java.util.Iterator<E> iterator();
-    method public int lastIndexOf(E, int);
     method public int lastIndexOf(java.lang.Object);
-    method public java.util.ListIterator<E> listIterator(int);
+    method public int lastIndexOf(E, int);
     method public java.util.ListIterator<E> listIterator();
-    method public synchronized E remove(int);
-    method public synchronized boolean remove(java.lang.Object);
-    method public synchronized boolean removeAll(java.util.Collection<?>);
-    method public synchronized boolean retainAll(java.util.Collection<?>);
-    method public synchronized E set(int, E);
+    method public java.util.ListIterator<E> listIterator(int);
+    method public E remove(int);
+    method public boolean remove(java.lang.Object);
+    method public boolean removeAll(java.util.Collection<?>);
+    method public boolean retainAll(java.util.Collection<?>);
+    method public E set(int, E);
     method public int size();
     method public java.util.List<E> subList(int, int);
     method public java.lang.Object[] toArray();
diff --git a/api/removed.txt b/api/removed.txt
index 683a695..10e6eb5 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -78,10 +78,25 @@
     enum_constant public static final android.graphics.AvoidXfermode.Mode TARGET;
   }
 
+  public deprecated class LayerRasterizer extends android.graphics.Rasterizer {
+    ctor public LayerRasterizer();
+    method public void addLayer(android.graphics.Paint, float, float);
+    method public void addLayer(android.graphics.Paint);
+  }
+
+  public class Paint {
+    method public deprecated android.graphics.Rasterizer getRasterizer();
+    method public deprecated android.graphics.Rasterizer setRasterizer(android.graphics.Rasterizer);
+  }
+
   public deprecated class PixelXorXfermode extends android.graphics.Xfermode {
     ctor public PixelXorXfermode(int);
   }
 
+  public class Rasterizer {
+    ctor public Rasterizer();
+  }
+
 }
 
 package android.location {
@@ -393,6 +408,15 @@
 
 }
 
+package android.text.style {
+
+  public class RasterizerSpan extends android.text.style.CharacterStyle implements android.text.style.UpdateAppearance {
+    ctor public RasterizerSpan(android.graphics.Rasterizer);
+    method public android.graphics.Rasterizer getRasterizer();
+  }
+
+}
+
 package android.util {
 
   public deprecated class FloatMath {
diff --git a/api/system-current.txt b/api/system-current.txt
index 41fd0d4..870070b 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -857,6 +857,8 @@
     field public static final int keyWidth = 16843325; // 0x101023d
     field public static final int keyboardLayout = 16843691; // 0x10103ab
     field public static final int keyboardMode = 16843341; // 0x101024d
+    field public static final int keyboardNavigationCluster = 16844096; // 0x1010540
+    field public static final int keyboardNavigationSection = 16844097; // 0x1010541
     field public static final int keycode = 16842949; // 0x10100c5
     field public static final int killAfterRestore = 16843420; // 0x101029c
     field public static final int label = 16842753; // 0x1010001
@@ -1000,11 +1002,13 @@
     field public static final int negativeButtonText = 16843254; // 0x10101f6
     field public static final int nestedScrollingEnabled = 16843830; // 0x1010436
     field public static final int networkSecurityConfig = 16844071; // 0x1010527
+    field public static final int nextClusterForward = 16844098; // 0x1010542
     field public static final int nextFocusDown = 16842980; // 0x10100e4
     field public static final int nextFocusForward = 16843580; // 0x101033c
     field public static final int nextFocusLeft = 16842977; // 0x10100e1
     field public static final int nextFocusRight = 16842978; // 0x10100e2
     field public static final int nextFocusUp = 16842979; // 0x10100e3
+    field public static final int nextSectionForward = 16844099; // 0x1010543
     field public static final int noHistory = 16843309; // 0x101022d
     field public static final int normalScreens = 16843397; // 0x1010285
     field public static final int notificationTimeout = 16843651; // 0x1010383
@@ -3772,6 +3776,7 @@
     method public void setIntent(android.content.Intent);
     method public final void setMediaController(android.media.session.MediaController);
     method public void setOverlayWithDecorCaptionEnabled(boolean);
+    method public void setPictureInPictureActions(java.util.List<android.app.RemoteAction>);
     method public void setPictureInPictureAspectRatio(float);
     method public final deprecated void setProgress(int);
     method public final deprecated void setProgressBarIndeterminate(boolean);
@@ -3858,6 +3863,7 @@
     method public int getLauncherLargeIconDensity();
     method public int getLauncherLargeIconSize();
     method public int getLockTaskModeState();
+    method public static int getMaxNumPictureInPictureActions();
     method public int getMemoryClass();
     method public void getMemoryInfo(android.app.ActivityManager.MemoryInfo);
     method public static void getMyMemoryState(android.app.ActivityManager.RunningAppProcessInfo);
@@ -5141,6 +5147,7 @@
     method public java.lang.String getChannel();
     method public java.lang.String getGroup();
     method public android.graphics.drawable.Icon getLargeIcon();
+    method public static java.lang.Class<? extends android.app.Notification.Style> getNotificationStyleClass(java.lang.String);
     method public android.graphics.drawable.Icon getSmallIcon();
     method public java.lang.String getSortKey();
     method public void writeToParcel(android.os.Parcel, int);
@@ -5710,6 +5717,22 @@
     field public static final int STYLE_SPINNER = 0; // 0x0
   }
 
+  public final class RemoteAction implements android.os.Parcelable {
+    ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.RemoteAction.OnActionListener);
+    method public android.app.RemoteAction clone();
+    method public int describeContents();
+    method public void dump(java.lang.String, java.io.PrintWriter);
+    method public java.lang.CharSequence getContentDescription();
+    method public android.graphics.drawable.Icon getIcon();
+    method public java.lang.CharSequence getTitle();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.RemoteAction> CREATOR;
+  }
+
+  public static abstract interface RemoteAction.OnActionListener {
+    method public abstract void onAction(android.app.RemoteAction);
+  }
+
   public final class RemoteInput implements android.os.Parcelable {
     method public static void addResultsToIntent(android.app.RemoteInput[], android.content.Intent, android.os.Bundle);
     method public int describeContents();
@@ -6280,6 +6303,8 @@
     method public boolean isCallerApplicationRestrictionsManagingPackage();
     method public boolean isDeviceManaged();
     method public boolean isDeviceOwnerApp(java.lang.String);
+    method public boolean isDeviceProvisioned();
+    method public boolean isDeviceProvisioningConfigApplied();
     method public boolean isLockTaskPermitted(java.lang.String);
     method public boolean isManagedProfile(android.content.ComponentName);
     method public boolean isMasterVolumeMuted(android.content.ComponentName);
@@ -6315,6 +6340,7 @@
     method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
     method public void setCrossProfileContactsSearchDisabled(android.content.ComponentName, boolean);
     method public void setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.CharSequence);
+    method public void setDeviceProvisioningConfigApplied();
     method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
     method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
@@ -6391,6 +6417,9 @@
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
     field public static final deprecated java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM";
+    field public static final java.lang.String EXTRA_PROVISIONING_DISCLAIMERS = "android.app.extra.PROVISIONING_DISCLAIMERS";
+    field public static final java.lang.String EXTRA_PROVISIONING_DISCLAIMER_CONTENT = "android.app.extra.PROVISIONING_DISCLAIMER_CONTENT";
+    field public static final java.lang.String EXTRA_PROVISIONING_DISCLAIMER_HEADER = "android.app.extra.PROVISIONING_DISCLAIMER_HEADER";
     field public static final java.lang.String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.PROVISIONING_EMAIL_ADDRESS";
     field public static final java.lang.String EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION = "android.app.extra.PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION";
     field public static final java.lang.String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
@@ -8731,6 +8760,7 @@
     field public static final java.lang.String TELECOM_SERVICE = "telecom";
     field public static final java.lang.String TELEPHONY_SERVICE = "phone";
     field public static final java.lang.String TELEPHONY_SUBSCRIPTION_SERVICE = "telephony_subscription_service";
+    field public static final java.lang.String TEXT_CLASSIFICATION_SERVICE = "textclassification";
     field public static final java.lang.String TEXT_SERVICES_MANAGER_SERVICE = "textservices";
     field public static final java.lang.String TV_INPUT_SERVICE = "tv_input";
     field public static final java.lang.String UI_MODE_SERVICE = "uimode";
@@ -9088,6 +9118,7 @@
     field public static final java.lang.String ACTION_EDIT = "android.intent.action.EDIT";
     field public static final java.lang.String ACTION_EXTERNAL_APPLICATIONS_AVAILABLE = "android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE";
     field public static final java.lang.String ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE = "android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE";
+    field public static final java.lang.String ACTION_FACTORY_RESET = "android.intent.action.FACTORY_RESET";
     field public static final java.lang.String ACTION_FACTORY_TEST = "android.intent.action.FACTORY_TEST";
     field public static final java.lang.String ACTION_GET_CONTENT = "android.intent.action.GET_CONTENT";
     field public static final java.lang.String ACTION_GET_RESTRICTION_ENTRIES = "android.intent.action.GET_RESTRICTION_ENTRIES";
@@ -9251,6 +9282,7 @@
     field public static final java.lang.String EXTRA_DONT_KILL_APP = "android.intent.extra.DONT_KILL_APP";
     field public static final java.lang.String EXTRA_EMAIL = "android.intent.extra.EMAIL";
     field public static final java.lang.String EXTRA_EXCLUDE_COMPONENTS = "android.intent.extra.EXCLUDE_COMPONENTS";
+    field public static final java.lang.String EXTRA_FORCE_FACTORY_RESET = "android.intent.extra.FORCE_FACTORY_RESET";
     field public static final java.lang.String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
     field public static final java.lang.String EXTRA_INDEX = "android.intent.extra.INDEX";
     field public static final java.lang.String EXTRA_INITIAL_INTENTS = "android.intent.extra.INITIAL_INTENTS";
@@ -10090,6 +10122,7 @@
 
   public class LauncherApps {
     method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
+    method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent);
     method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
     method public android.graphics.drawable.Drawable getShortcutIconDrawable(android.content.pm.ShortcutInfo, int);
     method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
@@ -10105,6 +10138,8 @@
     method public void startShortcut(java.lang.String, java.lang.String, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
     method public void startShortcut(android.content.pm.ShortcutInfo, android.graphics.Rect, android.os.Bundle);
     method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
+    field public static final java.lang.String ACTION_CONFIRM_PIN_ITEM = "android.content.pm.action.CONFIRM_PIN_ITEM";
+    field public static final java.lang.String EXTRA_PIN_ITEM_REQUEST = "android.content.pm.extra.PIN_ITEM_REQUEST";
   }
 
   public static abstract class LauncherApps.Callback {
@@ -10119,6 +10154,21 @@
     method public void onShortcutsChanged(java.lang.String, java.util.List<android.content.pm.ShortcutInfo>, android.os.UserHandle);
   }
 
+  public static final class LauncherApps.PinItemRequest implements android.os.Parcelable {
+    method public boolean accept(android.os.Bundle);
+    method public boolean accept();
+    method public int describeContents();
+    method public int getRequestType();
+    method public android.content.pm.ShortcutInfo getShortcutInfo();
+    method public boolean isValid();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.content.pm.LauncherApps.PinItemRequest> CREATOR;
+    field public static final int REQUEST_TYPE_SHORTCUT = 1; // 0x1
+  }
+
+  public static abstract class LauncherApps.PinItemRequest.RequestType implements java.lang.annotation.Annotation {
+  }
+
   public static class LauncherApps.ShortcutQuery {
     ctor public LauncherApps.ShortcutQuery();
     method public android.content.pm.LauncherApps.ShortcutQuery setActivity(android.content.ComponentName);
@@ -10756,9 +10806,11 @@
     method public int getMaxShortcutCountPerActivity();
     method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
     method public boolean isRateLimitingActive();
+    method public boolean isRequestPinShortcutSupported();
     method public void removeAllDynamicShortcuts();
     method public void removeDynamicShortcuts(java.util.List<java.lang.String>);
     method public void reportShortcutUsed(java.lang.String);
+    method public boolean requestPinShortcut(android.content.pm.ShortcutInfo, android.content.IntentSender);
     method public boolean setDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
     method public boolean updateShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
   }
@@ -12210,6 +12262,8 @@
     method public static android.graphics.Bitmap createBitmap(android.graphics.Bitmap, int, int, int, int, android.graphics.Matrix, boolean);
     method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config);
     method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config);
+    method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config, boolean);
+    method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config, boolean);
     method public static android.graphics.Bitmap createBitmap(int[], int, int, int, int, android.graphics.Bitmap.Config);
     method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int[], int, int, int, int, android.graphics.Bitmap.Config);
     method public static android.graphics.Bitmap createBitmap(int[], int, int, android.graphics.Bitmap.Config);
@@ -12273,6 +12327,8 @@
     enum_constant public static final android.graphics.Bitmap.Config ALPHA_8;
     enum_constant public static final deprecated android.graphics.Bitmap.Config ARGB_4444;
     enum_constant public static final android.graphics.Bitmap.Config ARGB_8888;
+    enum_constant public static final android.graphics.Bitmap.Config HARDWARE;
+    enum_constant public static final android.graphics.Bitmap.Config RGBA_F16;
     enum_constant public static final android.graphics.Bitmap.Config RGB_565;
   }
 
@@ -12632,6 +12688,7 @@
     method public android.graphics.Bitmap render();
     method public android.graphics.ColorSpace.Renderer showWhitePoint(boolean);
     method public android.graphics.ColorSpace.Renderer size(int);
+    method public android.graphics.ColorSpace.Renderer uniformChromaticityScale(boolean);
   }
 
   public static class ColorSpace.Rgb extends android.graphics.ColorSpace {
@@ -12733,12 +12790,6 @@
     enum_constant public static final android.graphics.Interpolator.Result NORMAL;
   }
 
-  public deprecated class LayerRasterizer extends android.graphics.Rasterizer {
-    ctor public LayerRasterizer();
-    method public void addLayer(android.graphics.Paint, float, float);
-    method public void addLayer(android.graphics.Paint);
-  }
-
   public class LightingColorFilter extends android.graphics.ColorFilter {
     ctor public LightingColorFilter(int, int);
   }
@@ -12900,7 +12951,6 @@
     method public int getOffsetForAdvance(char[], int, int, int, int, boolean, float);
     method public int getOffsetForAdvance(java.lang.CharSequence, int, int, int, int, boolean, float);
     method public android.graphics.PathEffect getPathEffect();
-    method public deprecated android.graphics.Rasterizer getRasterizer();
     method public float getRunAdvance(char[], int, int, int, int, boolean, int);
     method public float getRunAdvance(java.lang.CharSequence, int, int, int, int, boolean, int);
     method public android.graphics.Shader getShader();
@@ -12957,7 +13007,6 @@
     method public void setLinearText(boolean);
     method public android.graphics.MaskFilter setMaskFilter(android.graphics.MaskFilter);
     method public android.graphics.PathEffect setPathEffect(android.graphics.PathEffect);
-    method public deprecated android.graphics.Rasterizer setRasterizer(android.graphics.Rasterizer);
     method public android.graphics.Shader setShader(android.graphics.Shader);
     method public void setShadowLayer(float, float, float, int);
     method public void setStrikeThruText(boolean);
@@ -13175,7 +13224,9 @@
     field public static final deprecated int RGBA_4444 = 7; // 0x7
     field public static final deprecated int RGBA_5551 = 6; // 0x6
     field public static final int RGBA_8888 = 1; // 0x1
+    field public static final int RGBA_F16 = 22; // 0x16
     field public static final int RGBX_8888 = 2; // 0x2
+    field public static final int RGBX_F16 = 23; // 0x17
     field public static final deprecated int RGB_332 = 11; // 0xb
     field public static final int RGB_565 = 4; // 0x4
     field public static final int RGB_888 = 3; // 0x3
@@ -13264,10 +13315,6 @@
     ctor public RadialGradient(float, float, float, int, int, android.graphics.Shader.TileMode);
   }
 
-  public deprecated class Rasterizer {
-    ctor public Rasterizer();
-  }
-
   public final class Rect implements android.os.Parcelable {
     ctor public Rect();
     ctor public Rect(int, int, int, int);
@@ -15776,7 +15823,6 @@
   }
 
   public final class GeofenceHardware {
-    ctor public GeofenceHardware(android.hardware.location.IGeofenceHardware);
     method public boolean addGeofence(int, int, android.hardware.location.GeofenceHardwareRequest, android.hardware.location.GeofenceHardwareCallback);
     method public int[] getMonitoringTypes();
     method public int getStatusOfMonitoringType(int);
@@ -15851,46 +15897,6 @@
     method public void setUnknownTimer(int);
   }
 
-  public final class GeofenceHardwareRequestParcelable implements android.os.Parcelable {
-    ctor public GeofenceHardwareRequestParcelable(int, android.hardware.location.GeofenceHardwareRequest);
-    method public int describeContents();
-    method public int getId();
-    method public int getLastTransition();
-    method public double getLatitude();
-    method public double getLongitude();
-    method public int getMonitorTransitions();
-    method public int getNotificationResponsiveness();
-    method public double getRadius();
-    method public int getUnknownTimer();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.hardware.location.GeofenceHardwareRequestParcelable> CREATOR;
-  }
-
-  public abstract interface IGeofenceHardware implements android.os.IInterface {
-    method public abstract boolean addCircularFence(int, android.hardware.location.GeofenceHardwareRequestParcelable, android.hardware.location.IGeofenceHardwareCallback) throws android.os.RemoteException;
-    method public abstract int[] getMonitoringTypes() throws android.os.RemoteException;
-    method public abstract int getStatusOfMonitoringType(int) throws android.os.RemoteException;
-    method public abstract boolean pauseGeofence(int, int) throws android.os.RemoteException;
-    method public abstract boolean registerForMonitorStateChangeCallback(int, android.hardware.location.IGeofenceHardwareMonitorCallback) throws android.os.RemoteException;
-    method public abstract boolean removeGeofence(int, int) throws android.os.RemoteException;
-    method public abstract boolean resumeGeofence(int, int, int) throws android.os.RemoteException;
-    method public abstract void setFusedGeofenceHardware(android.location.IFusedGeofenceHardware) throws android.os.RemoteException;
-    method public abstract void setGpsGeofenceHardware(android.location.IGpsGeofenceHardware) throws android.os.RemoteException;
-    method public abstract boolean unregisterForMonitorStateChangeCallback(int, android.hardware.location.IGeofenceHardwareMonitorCallback) throws android.os.RemoteException;
-  }
-
-  public abstract interface IGeofenceHardwareCallback implements android.os.IInterface {
-    method public abstract void onGeofenceAdd(int, int) throws android.os.RemoteException;
-    method public abstract void onGeofencePause(int, int) throws android.os.RemoteException;
-    method public abstract void onGeofenceRemove(int, int) throws android.os.RemoteException;
-    method public abstract void onGeofenceResume(int, int) throws android.os.RemoteException;
-    method public abstract void onGeofenceTransition(int, int, android.location.Location, long, int) throws android.os.RemoteException;
-  }
-
-  public abstract interface IGeofenceHardwareMonitorCallback implements android.os.IInterface {
-    method public abstract void onMonitoringSystemChange(android.hardware.location.GeofenceHardwareMonitorEvent) throws android.os.RemoteException;
-  }
-
   public class MemoryRegion implements android.os.Parcelable {
     ctor public MemoryRegion(android.os.Parcel);
     method public int describeContents();
@@ -16498,6 +16504,10 @@
     field public static final int CONTROL = 1; // 0x1
     field public static final int CR = 2; // 0x2
     field public static final int EXTEND = 3; // 0x3
+    field public static final int E_BASE = 13; // 0xd
+    field public static final int E_BASE_GAZ = 14; // 0xe
+    field public static final int E_MODIFIER = 15; // 0xf
+    field public static final int GLUE_AFTER_ZWJ = 16; // 0x10
     field public static final int L = 4; // 0x4
     field public static final int LF = 5; // 0x5
     field public static final int LV = 6; // 0x6
@@ -16508,6 +16518,7 @@
     field public static final int SPACING_MARK = 10; // 0xa
     field public static final int T = 8; // 0x8
     field public static final int V = 9; // 0x9
+    field public static final int ZWJ = 17; // 0x11
   }
 
   public static abstract interface UCharacter.HangulSyllableType {
@@ -16520,6 +16531,9 @@
   }
 
   public static abstract interface UCharacter.JoiningGroup {
+    field public static final int AFRICAN_FEH = 86; // 0x56
+    field public static final int AFRICAN_NOON = 87; // 0x57
+    field public static final int AFRICAN_QAF = 88; // 0x58
     field public static final int AIN = 1; // 0x1
     field public static final int ALAPH = 2; // 0x2
     field public static final int ALEF = 3; // 0x3
@@ -16633,6 +16647,8 @@
     field public static final int CONDITIONAL_JAPANESE_STARTER = 37; // 0x25
     field public static final int CONTINGENT_BREAK = 7; // 0x7
     field public static final int EXCLAMATION = 11; // 0xb
+    field public static final int E_BASE = 40; // 0x28
+    field public static final int E_MODIFIER = 41; // 0x29
     field public static final int GLUE = 12; // 0xc
     field public static final int H2 = 31; // 0x1f
     field public static final int H3 = 32; // 0x20
@@ -16659,6 +16675,7 @@
     field public static final int SURROGATE = 25; // 0x19
     field public static final int UNKNOWN = 0; // 0x0
     field public static final int WORD_JOINER = 30; // 0x1e
+    field public static final int ZWJ = 42; // 0x2a
     field public static final int ZWSPACE = 28; // 0x1c
   }
 
@@ -16692,6 +16709,8 @@
     method public int getID();
     method public static android.icu.lang.UCharacter.UnicodeBlock getInstance(int);
     method public static android.icu.lang.UCharacter.UnicodeBlock of(int);
+    field public static final android.icu.lang.UCharacter.UnicodeBlock ADLAM;
+    field public static final int ADLAM_ID = 263; // 0x107
     field public static final android.icu.lang.UCharacter.UnicodeBlock AEGEAN_NUMBERS;
     field public static final int AEGEAN_NUMBERS_ID = 119; // 0x77
     field public static final android.icu.lang.UCharacter.UnicodeBlock AHOM;
@@ -16740,6 +16759,8 @@
     field public static final int BATAK_ID = 199; // 0xc7
     field public static final android.icu.lang.UCharacter.UnicodeBlock BENGALI;
     field public static final int BENGALI_ID = 16; // 0x10
+    field public static final android.icu.lang.UCharacter.UnicodeBlock BHAIKSUKI;
+    field public static final int BHAIKSUKI_ID = 264; // 0x108
     field public static final android.icu.lang.UCharacter.UnicodeBlock BLOCK_ELEMENTS;
     field public static final int BLOCK_ELEMENTS_ID = 53; // 0x35
     field public static final android.icu.lang.UCharacter.UnicodeBlock BOPOMOFO;
@@ -16829,6 +16850,8 @@
     field public static final int CYRILLIC_EXTENDED_A_ID = 158; // 0x9e
     field public static final android.icu.lang.UCharacter.UnicodeBlock CYRILLIC_EXTENDED_B;
     field public static final int CYRILLIC_EXTENDED_B_ID = 160; // 0xa0
+    field public static final android.icu.lang.UCharacter.UnicodeBlock CYRILLIC_EXTENDED_C;
+    field public static final int CYRILLIC_EXTENDED_C_ID = 265; // 0x109
     field public static final int CYRILLIC_ID = 9; // 0x9
     field public static final android.icu.lang.UCharacter.UnicodeBlock CYRILLIC_SUPPLEMENT;
     field public static final android.icu.lang.UCharacter.UnicodeBlock CYRILLIC_SUPPLEMENTARY;
@@ -16882,6 +16905,8 @@
     field public static final int GEORGIAN_SUPPLEMENT_ID = 135; // 0x87
     field public static final android.icu.lang.UCharacter.UnicodeBlock GLAGOLITIC;
     field public static final int GLAGOLITIC_ID = 136; // 0x88
+    field public static final android.icu.lang.UCharacter.UnicodeBlock GLAGOLITIC_SUPPLEMENT;
+    field public static final int GLAGOLITIC_SUPPLEMENT_ID = 266; // 0x10a
     field public static final android.icu.lang.UCharacter.UnicodeBlock GOTHIC;
     field public static final int GOTHIC_ID = 89; // 0x59
     field public static final android.icu.lang.UCharacter.UnicodeBlock GRANTHA;
@@ -16920,6 +16945,8 @@
     field public static final int HIRAGANA_ID = 62; // 0x3e
     field public static final android.icu.lang.UCharacter.UnicodeBlock IDEOGRAPHIC_DESCRIPTION_CHARACTERS;
     field public static final int IDEOGRAPHIC_DESCRIPTION_CHARACTERS_ID = 60; // 0x3c
+    field public static final android.icu.lang.UCharacter.UnicodeBlock IDEOGRAPHIC_SYMBOLS_AND_PUNCTUATION;
+    field public static final int IDEOGRAPHIC_SYMBOLS_AND_PUNCTUATION_ID = 267; // 0x10b
     field public static final android.icu.lang.UCharacter.UnicodeBlock IMPERIAL_ARAMAIC;
     field public static final int IMPERIAL_ARAMAIC_ID = 186; // 0xba
     field public static final android.icu.lang.UCharacter.UnicodeBlock INSCRIPTIONAL_PAHLAVI;
@@ -17004,6 +17031,8 @@
     field public static final int MANDAIC_ID = 198; // 0xc6
     field public static final android.icu.lang.UCharacter.UnicodeBlock MANICHAEAN;
     field public static final int MANICHAEAN_ID = 234; // 0xea
+    field public static final android.icu.lang.UCharacter.UnicodeBlock MARCHEN;
+    field public static final int MARCHEN_ID = 268; // 0x10c
     field public static final android.icu.lang.UCharacter.UnicodeBlock MATHEMATICAL_ALPHANUMERIC_SYMBOLS;
     field public static final int MATHEMATICAL_ALPHANUMERIC_SYMBOLS_ID = 93; // 0x5d
     field public static final android.icu.lang.UCharacter.UnicodeBlock MATHEMATICAL_OPERATORS;
@@ -17038,6 +17067,8 @@
     field public static final int MODI_ID = 236; // 0xec
     field public static final android.icu.lang.UCharacter.UnicodeBlock MONGOLIAN;
     field public static final int MONGOLIAN_ID = 37; // 0x25
+    field public static final android.icu.lang.UCharacter.UnicodeBlock MONGOLIAN_SUPPLEMENT;
+    field public static final int MONGOLIAN_SUPPLEMENT_ID = 269; // 0x10d
     field public static final android.icu.lang.UCharacter.UnicodeBlock MRO;
     field public static final int MRO_ID = 237; // 0xed
     field public static final android.icu.lang.UCharacter.UnicodeBlock MULTANI;
@@ -17052,6 +17083,8 @@
     field public static final int MYANMAR_ID = 28; // 0x1c
     field public static final android.icu.lang.UCharacter.UnicodeBlock NABATAEAN;
     field public static final int NABATAEAN_ID = 239; // 0xef
+    field public static final android.icu.lang.UCharacter.UnicodeBlock NEWA;
+    field public static final int NEWA_ID = 270; // 0x10e
     field public static final android.icu.lang.UCharacter.UnicodeBlock NEW_TAI_LUE;
     field public static final int NEW_TAI_LUE_ID = 139; // 0x8b
     field public static final android.icu.lang.UCharacter.UnicodeBlock NKO;
@@ -17083,6 +17116,8 @@
     field public static final int ORIYA_ID = 19; // 0x13
     field public static final android.icu.lang.UCharacter.UnicodeBlock ORNAMENTAL_DINGBATS;
     field public static final int ORNAMENTAL_DINGBATS_ID = 242; // 0xf2
+    field public static final android.icu.lang.UCharacter.UnicodeBlock OSAGE;
+    field public static final int OSAGE_ID = 271; // 0x10f
     field public static final android.icu.lang.UCharacter.UnicodeBlock OSMANYA;
     field public static final int OSMANYA_ID = 122; // 0x7a
     field public static final android.icu.lang.UCharacter.UnicodeBlock PAHAWH_HMONG;
@@ -17185,6 +17220,10 @@
     field public static final int TAKRI_ID = 220; // 0xdc
     field public static final android.icu.lang.UCharacter.UnicodeBlock TAMIL;
     field public static final int TAMIL_ID = 20; // 0x14
+    field public static final android.icu.lang.UCharacter.UnicodeBlock TANGUT;
+    field public static final android.icu.lang.UCharacter.UnicodeBlock TANGUT_COMPONENTS;
+    field public static final int TANGUT_COMPONENTS_ID = 273; // 0x111
+    field public static final int TANGUT_ID = 272; // 0x110
     field public static final android.icu.lang.UCharacter.UnicodeBlock TELUGU;
     field public static final int TELUGU_ID = 21; // 0x15
     field public static final android.icu.lang.UCharacter.UnicodeBlock THAANA;
@@ -17231,7 +17270,11 @@
     field public static final int DOUBLE_QUOTE = 16; // 0x10
     field public static final int EXTEND = 9; // 0x9
     field public static final int EXTENDNUMLET = 7; // 0x7
+    field public static final int E_BASE = 17; // 0x11
+    field public static final int E_BASE_GAZ = 18; // 0x12
+    field public static final int E_MODIFIER = 19; // 0x13
     field public static final int FORMAT = 2; // 0x2
+    field public static final int GLUE_AFTER_ZWJ = 20; // 0x14
     field public static final int HEBREW_LETTER = 14; // 0xe
     field public static final int KATAKANA = 3; // 0x3
     field public static final int LF = 10; // 0xa
@@ -17243,6 +17286,7 @@
     field public static final int OTHER = 0; // 0x0
     field public static final int REGIONAL_INDICATOR = 13; // 0xd
     field public static final int SINGLE_QUOTE = 15; // 0xf
+    field public static final int ZWJ = 21; // 0x15
   }
 
   public final class UCharacterCategory implements android.icu.lang.UCharacterEnums.ECharacterCategory {
@@ -17461,6 +17505,7 @@
     method public static final boolean hasScript(int, int);
     method public static final boolean isCased(int);
     method public static final boolean isRightToLeft(int);
+    field public static final int ADLAM = 167; // 0xa7
     field public static final int AFAKA = 147; // 0x93
     field public static final int AHOM = 161; // 0xa1
     field public static final int ANATOLIAN_HIEROGLYPHS = 156; // 0x9c
@@ -17472,6 +17517,7 @@
     field public static final int BASSA_VAH = 134; // 0x86
     field public static final int BATAK = 63; // 0x3f
     field public static final int BENGALI = 4; // 0x4
+    field public static final int BHAIKSUKI = 168; // 0xa8
     field public static final int BLISSYMBOLS = 64; // 0x40
     field public static final int BOOK_PAHLAVI = 124; // 0x7c
     field public static final int BOPOMOFO = 5; // 0x5
@@ -17510,6 +17556,7 @@
     field public static final int HAN = 17; // 0x11
     field public static final int HANGUL = 18; // 0x12
     field public static final int HANUNOO = 43; // 0x2b
+    field public static final int HAN_WITH_BOPOMOFO = 172; // 0xac
     field public static final int HARAPPAN_INDUS = 77; // 0x4d
     field public static final int HATRAN = 162; // 0xa2
     field public static final int HEBREW = 19; // 0x13
@@ -17520,6 +17567,7 @@
     field public static final int INSCRIPTIONAL_PAHLAVI = 122; // 0x7a
     field public static final int INSCRIPTIONAL_PARTHIAN = 125; // 0x7d
     field public static final int INVALID_CODE = -1; // 0xffffffff
+    field public static final int JAMO = 173; // 0xad
     field public static final int JAPANESE = 105; // 0x69
     field public static final int JAVANESE = 78; // 0x4e
     field public static final int JURCHEN = 148; // 0x94
@@ -17553,6 +17601,7 @@
     field public static final int MANDAEAN = 84; // 0x54
     field public static final int MANDAIC = 84; // 0x54
     field public static final int MANICHAEAN = 121; // 0x79
+    field public static final int MARCHEN = 169; // 0xa9
     field public static final int MATHEMATICAL_NOTATION = 128; // 0x80
     field public static final int MAYAN_HIEROGLYPHS = 85; // 0x55
     field public static final int MEITEI_MAYEK = 115; // 0x73
@@ -17569,6 +17618,7 @@
     field public static final int MYANMAR = 28; // 0x1c
     field public static final int NABATAEAN = 143; // 0x8f
     field public static final int NAKHI_GEBA = 132; // 0x84
+    field public static final int NEWA = 170; // 0xaa
     field public static final int NEW_TAI_LUE = 59; // 0x3b
     field public static final int NKO = 87; // 0x57
     field public static final int NUSHU = 150; // 0x96
@@ -17583,6 +17633,7 @@
     field public static final int OL_CHIKI = 109; // 0x6d
     field public static final int ORIYA = 31; // 0x1f
     field public static final int ORKHON = 88; // 0x58
+    field public static final int OSAGE = 171; // 0xab
     field public static final int OSMANYA = 50; // 0x32
     field public static final int PAHAWH_HMONG = 75; // 0x4b
     field public static final int PALMYRENE = 144; // 0x90
@@ -17608,6 +17659,7 @@
     field public static final int SUNDANESE = 113; // 0x71
     field public static final int SYLOTI_NAGRI = 58; // 0x3a
     field public static final int SYMBOLS = 129; // 0x81
+    field public static final int SYMBOLS_EMOJI = 174; // 0xae
     field public static final int SYRIAC = 34; // 0x22
     field public static final int TAGALOG = 42; // 0x2a
     field public static final int TAGBANWA = 45; // 0x2d
@@ -18134,6 +18186,8 @@
     method public static final android.icu.text.DateFormat.BooleanAttribute[] values();
     enum_constant public static final android.icu.text.DateFormat.BooleanAttribute PARSE_ALLOW_NUMERIC;
     enum_constant public static final android.icu.text.DateFormat.BooleanAttribute PARSE_ALLOW_WHITESPACE;
+    enum_constant public static final android.icu.text.DateFormat.BooleanAttribute PARSE_MULTIPLE_PATTERNS_FOR_MATCH;
+    enum_constant public static final android.icu.text.DateFormat.BooleanAttribute PARSE_PARTIAL_LITERAL_MATCH;
   }
 
   public static class DateFormat.Field extends java.text.Format.Field {
@@ -18818,6 +18872,7 @@
     field public static final int PERCENTSTYLE = 2; // 0x2
     field public static final int PLURALCURRENCYSTYLE = 6; // 0x6
     field public static final int SCIENTIFICSTYLE = 3; // 0x3
+    field public static final int STANDARDCURRENCYSTYLE = 9; // 0x9
   }
 
   public static class NumberFormat.Field extends java.text.Format.Field {
@@ -19612,7 +19667,7 @@
     field public static final int AM_PM = 9; // 0x9
     field public static final int APRIL = 3; // 0x3
     field public static final int AUGUST = 7; // 0x7
-    field protected static final int BASE_FIELD_COUNT = 23; // 0x17
+    field protected static final deprecated int BASE_FIELD_COUNT = 23; // 0x17
     field public static final int DATE = 5; // 0x5
     field public static final int DAY_OF_MONTH = 5; // 0x5
     field public static final int DAY_OF_WEEK = 7; // 0x7
@@ -19640,7 +19695,7 @@
     field public static final int MARCH = 2; // 0x2
     field protected static final int MAXIMUM = 3; // 0x3
     field protected static final java.util.Date MAX_DATE;
-    field protected static final int MAX_FIELD_COUNT = 32; // 0x20
+    field protected static final deprecated int MAX_FIELD_COUNT = 32; // 0x20
     field protected static final int MAX_JULIAN = 2130706432; // 0x7f000000
     field protected static final long MAX_MILLIS = 183882168921600000L; // 0x28d47dbbf19b000L
     field public static final int MAY = 4; // 0x4
@@ -19960,6 +20015,7 @@
     field public static final android.icu.util.MeasureUnit CELSIUS;
     field public static final android.icu.util.MeasureUnit CENTILITER;
     field public static final android.icu.util.MeasureUnit CENTIMETER;
+    field public static final android.icu.util.MeasureUnit CENTURY;
     field public static final android.icu.util.MeasureUnit CUBIC_CENTIMETER;
     field public static final android.icu.util.MeasureUnit CUBIC_FOOT;
     field public static final android.icu.util.MeasureUnit CUBIC_INCH;
@@ -19968,6 +20024,7 @@
     field public static final android.icu.util.MeasureUnit CUBIC_MILE;
     field public static final android.icu.util.MeasureUnit CUBIC_YARD;
     field public static final android.icu.util.MeasureUnit CUP;
+    field public static final android.icu.util.MeasureUnit CUP_METRIC;
     field public static final android.icu.util.TimeUnit DAY;
     field public static final android.icu.util.MeasureUnit DECILITER;
     field public static final android.icu.util.MeasureUnit DECIMETER;
@@ -19979,6 +20036,7 @@
     field public static final android.icu.util.MeasureUnit FOOT;
     field public static final android.icu.util.MeasureUnit FURLONG;
     field public static final android.icu.util.MeasureUnit GALLON;
+    field public static final android.icu.util.MeasureUnit GENERIC_TEMPERATURE;
     field public static final android.icu.util.MeasureUnit GIGABIT;
     field public static final android.icu.util.MeasureUnit GIGABYTE;
     field public static final android.icu.util.MeasureUnit GIGAHERTZ;
@@ -20006,8 +20064,10 @@
     field public static final android.icu.util.MeasureUnit KILOMETER_PER_HOUR;
     field public static final android.icu.util.MeasureUnit KILOWATT;
     field public static final android.icu.util.MeasureUnit KILOWATT_HOUR;
+    field public static final android.icu.util.MeasureUnit KNOT;
     field public static final android.icu.util.MeasureUnit LIGHT_YEAR;
     field public static final android.icu.util.MeasureUnit LITER;
+    field public static final android.icu.util.MeasureUnit LITER_PER_100KILOMETERS;
     field public static final android.icu.util.MeasureUnit LITER_PER_KILOMETER;
     field public static final android.icu.util.MeasureUnit LUX;
     field public static final android.icu.util.MeasureUnit MEGABIT;
@@ -20025,6 +20085,7 @@
     field public static final android.icu.util.MeasureUnit MILE;
     field public static final android.icu.util.MeasureUnit MILE_PER_GALLON;
     field public static final android.icu.util.MeasureUnit MILE_PER_HOUR;
+    field public static final android.icu.util.MeasureUnit MILE_SCANDINAVIAN;
     field public static final android.icu.util.MeasureUnit MILLIAMPERE;
     field public static final android.icu.util.MeasureUnit MILLIBAR;
     field public static final android.icu.util.MeasureUnit MILLIGRAM;
@@ -20044,10 +20105,12 @@
     field public static final android.icu.util.MeasureUnit PARSEC;
     field public static final android.icu.util.MeasureUnit PICOMETER;
     field public static final android.icu.util.MeasureUnit PINT;
+    field public static final android.icu.util.MeasureUnit PINT_METRIC;
     field public static final android.icu.util.MeasureUnit POUND;
     field public static final android.icu.util.MeasureUnit POUND_PER_SQUARE_INCH;
     field public static final android.icu.util.MeasureUnit QUART;
     field public static final android.icu.util.MeasureUnit RADIAN;
+    field public static final android.icu.util.MeasureUnit REVOLUTION_ANGLE;
     field public static final android.icu.util.TimeUnit SECOND;
     field public static final android.icu.util.MeasureUnit SQUARE_CENTIMETER;
     field public static final android.icu.util.MeasureUnit SQUARE_FOOT;
@@ -20359,6 +20422,7 @@
     field public static final android.icu.util.VersionInfo UNICODE_6_3;
     field public static final android.icu.util.VersionInfo UNICODE_7_0;
     field public static final android.icu.util.VersionInfo UNICODE_8_0;
+    field public static final android.icu.util.VersionInfo UNICODE_9_0;
   }
 
 }
@@ -21139,23 +21203,6 @@
     method public abstract void onNmeaReceived(long, java.lang.String);
   }
 
-  public abstract interface IFusedGeofenceHardware implements android.os.IInterface {
-    method public abstract void addGeofences(android.hardware.location.GeofenceHardwareRequestParcelable[]) throws android.os.RemoteException;
-    method public abstract boolean isSupported() throws android.os.RemoteException;
-    method public abstract void modifyGeofenceOptions(int, int, int, int, int, int) throws android.os.RemoteException;
-    method public abstract void pauseMonitoringGeofence(int) throws android.os.RemoteException;
-    method public abstract void removeGeofences(int[]) throws android.os.RemoteException;
-    method public abstract void resumeMonitoringGeofence(int, int) throws android.os.RemoteException;
-  }
-
-  public abstract interface IGpsGeofenceHardware implements android.os.IInterface {
-    method public abstract boolean addCircularHardwareGeofence(int, double, double, double, int, int, int, int) throws android.os.RemoteException;
-    method public abstract boolean isHardwareGeofenceSupported() throws android.os.RemoteException;
-    method public abstract boolean pauseHardwareGeofence(int) throws android.os.RemoteException;
-    method public abstract boolean removeHardwareGeofence(int) throws android.os.RemoteException;
-    method public abstract boolean resumeHardwareGeofence(int, int) throws android.os.RemoteException;
-  }
-
   public class Location implements android.os.Parcelable {
     ctor public Location(java.lang.String);
     ctor public Location(android.location.Location);
@@ -24258,6 +24305,7 @@
     method public android.content.ComponentName getServiceComponent();
     method public android.media.session.MediaSession.Token getSessionToken();
     method public boolean isConnected();
+    method public void search(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SearchCallback);
     method public void subscribe(java.lang.String, android.media.browse.MediaBrowser.SubscriptionCallback);
     method public void subscribe(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SubscriptionCallback);
     method public void unsubscribe(java.lang.String);
@@ -24293,6 +24341,12 @@
     field public static final int FLAG_PLAYABLE = 2; // 0x2
   }
 
+  public static abstract class MediaBrowser.SearchCallback {
+    ctor public MediaBrowser.SearchCallback();
+    method public void onError(java.lang.String, android.os.Bundle);
+    method public void onSearchResult(java.lang.String, android.os.Bundle, java.util.List<android.media.browse.MediaBrowser.MediaItem>);
+  }
+
   public static abstract class MediaBrowser.SubscriptionCallback {
     ctor public MediaBrowser.SubscriptionCallback();
     method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>);
@@ -25997,11 +26051,16 @@
   public abstract class NetworkRecommendationProvider {
     ctor public NetworkRecommendationProvider(android.os.Handler);
     method public final android.os.IBinder getBinder();
-    method public abstract android.net.RecommendationResult onRequestRecommendation(android.net.RecommendationRequest);
+    method public abstract void onRequestRecommendation(android.net.RecommendationRequest, android.net.NetworkRecommendationProvider.ResultCallback);
+    method public abstract void onRequestScores(android.net.NetworkKey[]);
     field public static final java.lang.String EXTRA_RECOMMENDATION_RESULT = "android.net.extra.RECOMMENDATION_RESULT";
     field public static final java.lang.String EXTRA_SEQUENCE = "android.net.extra.SEQUENCE";
   }
 
+  public static final class NetworkRecommendationProvider.ResultCallback {
+    method public void onResult(android.net.RecommendationResult);
+  }
+
   public class NetworkRequest implements android.os.Parcelable {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
@@ -31681,6 +31740,27 @@
     method public abstract android.os.IBinder asBinder();
   }
 
+  public class IncidentManager {
+    method public void reportIncident(android.os.IncidentReportArgs);
+    method public void reportIncident(java.lang.String, byte[]);
+  }
+
+  public final class IncidentReportArgs implements android.os.Parcelable {
+    ctor public IncidentReportArgs();
+    ctor public IncidentReportArgs(android.os.Parcel);
+    method public void addHeader(byte[]);
+    method public void addSection(int);
+    method public boolean containsSection(int);
+    method public int describeContents();
+    method public boolean isAll();
+    method public static android.os.IncidentReportArgs parseSetting(java.lang.String) throws java.lang.IllegalArgumentException;
+    method public void readFromParcel(android.os.Parcel);
+    method public int sectionCount();
+    method public void setAll(boolean);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.os.IncidentReportArgs> CREATOR;
+  }
+
   public final class LocaleList implements android.os.Parcelable {
     ctor public LocaleList(java.util.Locale...);
     method public int describeContents();
@@ -32368,6 +32448,7 @@
     method public deprecated void setUserRestrictions(android.os.Bundle, android.os.UserHandle);
     method public static boolean supportsMultipleUsers();
     field public static final java.lang.String ALLOW_PARENT_PROFILE_APP_LINKING = "allow_parent_profile_app_linking";
+    field public static final java.lang.String DISALLOW_ADD_MANAGED_PROFILE = "no_add_managed_profile";
     field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user";
     field public static final java.lang.String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
     field public static final java.lang.String DISALLOW_APPS_CONTROL = "no_control_apps";
@@ -32390,8 +32471,10 @@
     field public static final java.lang.String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";
     field public static final java.lang.String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media";
     field public static final java.lang.String DISALLOW_NETWORK_RESET = "no_network_reset";
+    field public static final java.lang.String DISALLOW_OEM_UNLOCK = "no_oem_unlock";
     field public static final java.lang.String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam";
     field public static final java.lang.String DISALLOW_OUTGOING_CALLS = "no_outgoing_calls";
+    field public static final java.lang.String DISALLOW_REMOVE_MANAGED_PROFILE = "no_remove_managed_profile";
     field public static final java.lang.String DISALLOW_REMOVE_USER = "no_remove_user";
     field public static final java.lang.String DISALLOW_SAFE_BOOT = "no_safe_boot";
     field public static final java.lang.String DISALLOW_SET_USER_ICON = "no_set_user_icon";
@@ -37709,7 +37792,8 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConnected();
     method public void onDisconnected();
-    method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.CancellationSignal, android.service.autofill.FillCallback);
+    method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback);
+    method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.SaveCallback);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
   }
 
@@ -37727,6 +37811,11 @@
     method public android.service.autofill.FillCallback.FillData.Builder setTextField(int, java.lang.String);
   }
 
+  public final class SaveCallback {
+    method public void onFailure(java.lang.CharSequence);
+    method public void onSuccess(int[]);
+  }
+
 }
 
 package android.service.carrier {
@@ -37908,6 +37997,7 @@
     method public abstract void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>);
     method public void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>, android.os.Bundle);
     method public void onLoadItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>);
+    method public void onSearch(java.lang.String, android.os.Bundle, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>);
     method public void setSessionToken(android.media.session.MediaSession.Token);
     field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
   }
@@ -37997,8 +38087,12 @@
     ctor public NotificationAssistantService();
     method public final void adjustNotification(android.service.notification.Adjustment);
     method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>);
+    method public void createNotificationChannel(java.lang.String, android.app.NotificationChannel);
+    method public void deleteNotificationChannel(java.lang.String, java.lang.String);
+    method public java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String);
     method public final android.os.IBinder onBind(android.content.Intent);
     method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+    method public void updateNotificationChannel(java.lang.String, android.app.NotificationChannel);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
   }
 
@@ -40470,6 +40564,7 @@
     field public static final java.lang.String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
     field public static final java.lang.String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
     field public static final java.lang.String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool";
+    field public static final java.lang.String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
     field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
     field public static final java.lang.String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
     field public static final java.lang.String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
@@ -41045,6 +41140,7 @@
     method public java.lang.String getSimOperatorName();
     method public java.lang.String getSimSerialNumber();
     method public int getSimState();
+    method public int getSimState(int);
     method public java.lang.String getSubscriberId();
     method public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
     method public java.lang.String getVoiceMailAlphaTag();
@@ -41160,7 +41256,11 @@
     field public static final int SIM_ACTIVATION_RESULT_IN_PROGRESS = 2; // 0x2
     field public static final int SIM_ACTIVATION_RESULT_NOT_SUPPORTED = 1; // 0x1
     field public static final int SIM_STATE_ABSENT = 1; // 0x1
+    field public static final int SIM_STATE_CARD_IO_ERROR = 8; // 0x8
+    field public static final int SIM_STATE_CARD_RESTRICTED = 9; // 0x9
     field public static final int SIM_STATE_NETWORK_LOCKED = 4; // 0x4
+    field public static final int SIM_STATE_NOT_READY = 6; // 0x6
+    field public static final int SIM_STATE_PERM_DISABLED = 7; // 0x7
     field public static final int SIM_STATE_PIN_REQUIRED = 2; // 0x2
     field public static final int SIM_STATE_PUK_REQUIRED = 3; // 0x3
     field public static final int SIM_STATE_READY = 5; // 0x5
@@ -41938,7 +42038,7 @@
     method public java.lang.CharSequence subSequence(int, int);
   }
 
-  public class AndroidCharacter {
+  public deprecated class AndroidCharacter {
     ctor public AndroidCharacter();
     method public static void getDirectionalities(char[], byte[], int);
     method public static int getEastAsianWidth(char);
@@ -42432,6 +42532,12 @@
     method public java.util.Map<java.lang.String, java.lang.Float> getTypeConfidence();
   }
 
+  public final class TextClassificationManager implements android.text.TextAssistant {
+    method public void addLinks(android.text.Spannable, int);
+    method public java.util.List<android.text.TextLanguage> detectLanguages(java.lang.CharSequence);
+    method public android.text.TextSelection suggestSelection(java.lang.CharSequence, int, int);
+  }
+
   public abstract interface TextDirectionHeuristic {
     method public abstract boolean isRtl(char[], int, int);
     method public abstract boolean isRtl(java.lang.CharSequence, int, int);
@@ -42447,6 +42553,13 @@
     field public static final android.text.TextDirectionHeuristic RTL;
   }
 
+  public final class TextLanguage {
+    ctor public TextLanguage(int, int, java.util.Map<java.lang.String, java.lang.Float>);
+    method public int getEndIndex();
+    method public java.util.Map<java.lang.String, java.lang.Float> getLanguageConfidence();
+    method public int getStartIndex();
+  }
+
   public class TextPaint extends android.graphics.Paint {
     ctor public TextPaint();
     ctor public TextPaint(int);
@@ -43141,12 +43254,6 @@
     method public void writeToParcel(android.os.Parcel, int);
   }
 
-  public class RasterizerSpan extends android.text.style.CharacterStyle implements android.text.style.UpdateAppearance {
-    ctor public RasterizerSpan(android.graphics.Rasterizer);
-    method public android.graphics.Rasterizer getRasterizer();
-    method public void updateDrawState(android.text.TextPaint);
-  }
-
   public class RelativeSizeSpan extends android.text.style.MetricAffectingSpan implements android.text.ParcelableSpan {
     ctor public RelativeSizeSpan(float);
     ctor public RelativeSizeSpan(android.os.Parcel);
@@ -44794,6 +44901,7 @@
     method public android.view.View findNearestTouchable(android.view.ViewGroup, int, int, int, int[]);
     method public final android.view.View findNextFocus(android.view.ViewGroup, android.view.View, int);
     method public android.view.View findNextFocusFromRect(android.view.ViewGroup, android.graphics.Rect, int);
+    method public android.view.View findNextKeyboardNavigationCluster(android.view.ViewGroup, android.view.View, int);
     method public static android.view.FocusFinder getInstance();
   }
 
@@ -46086,6 +46194,7 @@
     method public void addChildrenForAccessibility(java.util.ArrayList<android.view.View>);
     method public void addFocusables(java.util.ArrayList<android.view.View>, int);
     method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
+    method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
     method public void addOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
     method public void addOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
     method public void addTouchables(java.util.ArrayList<android.view.View>);
@@ -46142,7 +46251,8 @@
     method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
     method public boolean dispatchNestedScroll(int, int, int, int, int[]);
     method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public void dispatchProvideStructure(android.view.ViewStructure);
+    method public deprecated void dispatchProvideStructure(android.view.ViewStructure);
+    method public void dispatchProvideStructure(android.view.ViewStructure, int);
     method protected void dispatchRestoreInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSaveInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSetActivated(boolean);
@@ -46239,11 +46349,13 @@
     method public final int getMeasuredWidthAndState();
     method public int getMinimumHeight();
     method public int getMinimumWidth();
+    method public int getNextClusterForwardId();
     method public int getNextFocusDownId();
     method public int getNextFocusForwardId();
     method public int getNextFocusLeftId();
     method public int getNextFocusRightId();
     method public int getNextFocusUpId();
+    method public int getNextSectionForwardId();
     method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
     method public android.view.ViewOutlineProvider getOutlineProvider();
     method public int getOverScrollMode();
@@ -46346,6 +46458,8 @@
     method public boolean isInEditMode();
     method public boolean isInLayout();
     method public boolean isInTouchMode();
+    method public final boolean isKeyboardNavigationCluster();
+    method public final boolean isKeyboardNavigationSection();
     method public boolean isLaidOut();
     method public boolean isLayoutDirectionResolved();
     method public boolean isLayoutRequested();
@@ -46368,6 +46482,7 @@
     method public boolean isVerticalFadingEdgeEnabled();
     method public boolean isVerticalScrollBarEnabled();
     method public void jumpDrawablesToCurrentState();
+    method public android.view.View keyboardNavigationClusterSearch(int);
     method public void layout(int, int, int, int);
     method public final void measure(int, int);
     method protected static int[] mergeDrawableStates(int[], int[]);
@@ -46408,8 +46523,10 @@
     method protected void onMeasure(int, int);
     method protected void onOverScrolled(int, int, boolean, boolean);
     method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public void onProvideStructure(android.view.ViewStructure);
-    method public void onProvideVirtualStructure(android.view.ViewStructure);
+    method public deprecated void onProvideStructure(android.view.ViewStructure);
+    method public void onProvideStructure(android.view.ViewStructure, int);
+    method public deprecated void onProvideVirtualStructure(android.view.ViewStructure);
+    method public void onProvideVirtualStructure(android.view.ViewStructure, int);
     method public android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int);
     method protected void onRestoreInstanceState(android.os.Parcelable);
     method public void onRtlPropertiesChanged(int);
@@ -46512,6 +46629,8 @@
     method public void setId(int);
     method public void setImportantForAccessibility(int);
     method public void setKeepScreenOn(boolean);
+    method public void setKeyboardNavigationCluster(boolean);
+    method public void setKeyboardNavigationSection(boolean);
     method public void setLabelFor(int);
     method public void setLayerPaint(android.graphics.Paint);
     method public void setLayerType(int, android.graphics.Paint);
@@ -46523,11 +46642,13 @@
     method public void setMinimumHeight(int);
     method public void setMinimumWidth(int);
     method public void setNestedScrollingEnabled(boolean);
+    method public void setNextClusterForwardId(int);
     method public void setNextFocusDownId(int);
     method public void setNextFocusForwardId(int);
     method public void setNextFocusLeftId(int);
     method public void setNextFocusRightId(int);
     method public void setNextFocusUpId(int);
+    method public void setNextSectionForwardId(int);
     method public void setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener);
     method public void setOnClickListener(android.view.View.OnClickListener);
     method public void setOnContextClickListener(android.view.View.OnContextClickListener);
@@ -46611,6 +46732,8 @@
     field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
     field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
     field public static final android.util.Property<android.view.View, java.lang.Float> ALPHA;
+    field public static final int ASSIST_FLAG_NON_SANITIZED_TEXT = 2; // 0x2
+    field public static final int ASSIST_FLAG_SANITIZED_TEXT = 1; // 0x1
     field public static final int DRAG_FLAG_GLOBAL = 256; // 0x100
     field public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 64; // 0x40
     field public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 128; // 0x80
@@ -47007,6 +47130,7 @@
     method protected deprecated boolean isChildrenDrawnWithCacheEnabled();
     method public boolean isMotionEventSplittingEnabled();
     method public boolean isTransitionGroup();
+    method public android.view.View keyboardNavigationClusterSearch(android.view.View, int);
     method public final void layout(int, int, int, int);
     method protected void measureChild(android.view.View, int, int);
     method protected void measureChildWithMargins(android.view.View, int, int, int, int);
@@ -47169,6 +47293,7 @@
     method public abstract boolean isLayoutRequested();
     method public abstract boolean isTextAlignmentResolved();
     method public abstract boolean isTextDirectionResolved();
+    method public abstract android.view.View keyboardNavigationClusterSearch(android.view.View, int);
     method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
     method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
     method public abstract boolean onNestedPreFling(android.view.View, float, float);
@@ -49981,6 +50106,7 @@
     method public abstract void onMeasure(int, int);
     method public abstract void onOverScrolled(int, int, boolean, boolean);
     method public abstract void onProvideVirtualStructure(android.view.ViewStructure);
+    method public default void onProvideVirtualStructure(android.view.ViewStructure, int);
     method public abstract void onScrollChanged(int, int, int, int);
     method public abstract void onSizeChanged(int, int, int, int);
     method public abstract void onStartTemporaryDetach();
@@ -63430,6 +63556,10 @@
     ctor public Locale(java.lang.String, java.lang.String);
     ctor public Locale(java.lang.String);
     method public java.lang.Object clone();
+    method public static java.util.List<java.util.Locale> filter(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.util.Locale>, java.util.Locale.FilteringMode);
+    method public static java.util.List<java.util.Locale> filter(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.util.Locale>);
+    method public static java.util.List<java.lang.String> filterTags(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.lang.String>, java.util.Locale.FilteringMode);
+    method public static java.util.List<java.lang.String> filterTags(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.lang.String>);
     method public static java.util.Locale forLanguageTag(java.lang.String);
     method public static java.util.Locale[] getAvailableLocales();
     method public java.lang.String getCountry();
@@ -63458,6 +63588,8 @@
     method public java.lang.String getUnicodeLocaleType(java.lang.String);
     method public java.lang.String getVariant();
     method public boolean hasExtensions();
+    method public static java.util.Locale lookup(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.util.Locale>);
+    method public static java.lang.String lookupTag(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.lang.String>);
     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();
@@ -63513,6 +63645,28 @@
     enum_constant public static final java.util.Locale.Category FORMAT;
   }
 
+  public static final class Locale.FilteringMode extends java.lang.Enum {
+    method public static java.util.Locale.FilteringMode valueOf(java.lang.String);
+    method public static final java.util.Locale.FilteringMode[] values();
+    enum_constant public static final java.util.Locale.FilteringMode AUTOSELECT_FILTERING;
+    enum_constant public static final java.util.Locale.FilteringMode EXTENDED_FILTERING;
+    enum_constant public static final java.util.Locale.FilteringMode IGNORE_EXTENDED_RANGES;
+    enum_constant public static final java.util.Locale.FilteringMode MAP_EXTENDED_RANGES;
+    enum_constant public static final java.util.Locale.FilteringMode REJECT_EXTENDED_RANGES;
+  }
+
+  public static final class Locale.LanguageRange {
+    ctor public Locale.LanguageRange(java.lang.String);
+    ctor public Locale.LanguageRange(java.lang.String, double);
+    method public java.lang.String getRange();
+    method public double getWeight();
+    method public static java.util.List<java.util.Locale.LanguageRange> mapEquivalents(java.util.List<java.util.Locale.LanguageRange>, java.util.Map<java.lang.String, java.util.List<java.lang.String>>);
+    method public static java.util.List<java.util.Locale.LanguageRange> parse(java.lang.String);
+    method public static java.util.List<java.util.Locale.LanguageRange> parse(java.lang.String, java.util.Map<java.lang.String, java.util.List<java.lang.String>>);
+    field public static final double MAX_WEIGHT = 1.0;
+    field public static final double MIN_WEIGHT = 0.0;
+  }
+
   public class LongSummaryStatistics implements java.util.function.IntConsumer java.util.function.LongConsumer {
     ctor public LongSummaryStatistics();
     method public void accept(int);
@@ -64796,31 +64950,31 @@
     ctor public CopyOnWriteArrayList();
     ctor public CopyOnWriteArrayList(java.util.Collection<? extends E>);
     ctor public CopyOnWriteArrayList(E[]);
-    method public synchronized boolean add(E);
-    method public synchronized void add(int, E);
-    method public synchronized boolean addAll(java.util.Collection<? extends E>);
-    method public synchronized boolean addAll(int, java.util.Collection<? extends E>);
-    method public synchronized int addAllAbsent(java.util.Collection<? extends E>);
-    method public synchronized boolean addIfAbsent(E);
-    method public synchronized void clear();
+    method public boolean add(E);
+    method public void add(int, E);
+    method public boolean addAll(java.util.Collection<? extends E>);
+    method public boolean addAll(int, java.util.Collection<? extends E>);
+    method public int addAllAbsent(java.util.Collection<? extends E>);
+    method public boolean addIfAbsent(E);
+    method public void clear();
     method public java.lang.Object clone();
     method public boolean contains(java.lang.Object);
     method public boolean containsAll(java.util.Collection<?>);
     method public void forEach(java.util.function.Consumer<? super E>);
     method public E get(int);
-    method public int indexOf(E, int);
     method public int indexOf(java.lang.Object);
+    method public int indexOf(E, int);
     method public boolean isEmpty();
     method public java.util.Iterator<E> iterator();
-    method public int lastIndexOf(E, int);
     method public int lastIndexOf(java.lang.Object);
-    method public java.util.ListIterator<E> listIterator(int);
+    method public int lastIndexOf(E, int);
     method public java.util.ListIterator<E> listIterator();
-    method public synchronized E remove(int);
-    method public synchronized boolean remove(java.lang.Object);
-    method public synchronized boolean removeAll(java.util.Collection<?>);
-    method public synchronized boolean retainAll(java.util.Collection<?>);
-    method public synchronized E set(int, E);
+    method public java.util.ListIterator<E> listIterator(int);
+    method public E remove(int);
+    method public boolean remove(java.lang.Object);
+    method public boolean removeAll(java.util.Collection<?>);
+    method public boolean retainAll(java.util.Collection<?>);
+    method public E set(int, E);
     method public int size();
     method public java.util.List<E> subList(int, int);
     method public java.lang.Object[] toArray();
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 98e7953..0919b8f 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -76,10 +76,25 @@
     enum_constant public static final android.graphics.AvoidXfermode.Mode TARGET;
   }
 
+  public deprecated class LayerRasterizer extends android.graphics.Rasterizer {
+    ctor public LayerRasterizer();
+    method public void addLayer(android.graphics.Paint, float, float);
+    method public void addLayer(android.graphics.Paint);
+  }
+
+  public class Paint {
+    method public deprecated android.graphics.Rasterizer getRasterizer();
+    method public deprecated android.graphics.Rasterizer setRasterizer(android.graphics.Rasterizer);
+  }
+
   public deprecated class PixelXorXfermode extends android.graphics.Xfermode {
     ctor public PixelXorXfermode(int);
   }
 
+  public class Rasterizer {
+    ctor public Rasterizer();
+  }
+
 }
 
 package android.location {
@@ -387,6 +402,15 @@
 
 }
 
+package android.text.style {
+
+  public class RasterizerSpan extends android.text.style.CharacterStyle implements android.text.style.UpdateAppearance {
+    ctor public RasterizerSpan(android.graphics.Rasterizer);
+    method public android.graphics.Rasterizer getRasterizer();
+  }
+
+}
+
 package android.util {
 
   public deprecated class FloatMath {
diff --git a/api/test-current.txt b/api/test-current.txt
index 2a347d7..10554ff 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -750,6 +750,8 @@
     field public static final int keyWidth = 16843325; // 0x101023d
     field public static final int keyboardLayout = 16843691; // 0x10103ab
     field public static final int keyboardMode = 16843341; // 0x101024d
+    field public static final int keyboardNavigationCluster = 16844096; // 0x1010540
+    field public static final int keyboardNavigationSection = 16844097; // 0x1010541
     field public static final int keycode = 16842949; // 0x10100c5
     field public static final int killAfterRestore = 16843420; // 0x101029c
     field public static final int label = 16842753; // 0x1010001
@@ -893,11 +895,13 @@
     field public static final int negativeButtonText = 16843254; // 0x10101f6
     field public static final int nestedScrollingEnabled = 16843830; // 0x1010436
     field public static final int networkSecurityConfig = 16844071; // 0x1010527
+    field public static final int nextClusterForward = 16844098; // 0x1010542
     field public static final int nextFocusDown = 16842980; // 0x10100e4
     field public static final int nextFocusForward = 16843580; // 0x101033c
     field public static final int nextFocusLeft = 16842977; // 0x10100e1
     field public static final int nextFocusRight = 16842978; // 0x10100e2
     field public static final int nextFocusUp = 16842979; // 0x10100e3
+    field public static final int nextSectionForward = 16844099; // 0x1010543
     field public static final int noHistory = 16843309; // 0x101022d
     field public static final int normalScreens = 16843397; // 0x1010285
     field public static final int notificationTimeout = 16843651; // 0x1010383
@@ -3655,6 +3659,7 @@
     method public void setIntent(android.content.Intent);
     method public final void setMediaController(android.media.session.MediaController);
     method public void setOverlayWithDecorCaptionEnabled(boolean);
+    method public void setPictureInPictureActions(java.util.List<android.app.RemoteAction>);
     method public void setPictureInPictureAspectRatio(float);
     method public final deprecated void setProgress(int);
     method public final deprecated void setProgressBarIndeterminate(boolean);
@@ -3736,6 +3741,7 @@
     method public int getLauncherLargeIconDensity();
     method public int getLauncherLargeIconSize();
     method public int getLockTaskModeState();
+    method public static int getMaxNumPictureInPictureActions();
     method public int getMemoryClass();
     method public void getMemoryInfo(android.app.ActivityManager.MemoryInfo);
     method public static void getMyMemoryState(android.app.ActivityManager.RunningAppProcessInfo);
@@ -5554,6 +5560,22 @@
     field public static final int STYLE_SPINNER = 0; // 0x0
   }
 
+  public final class RemoteAction implements android.os.Parcelable {
+    ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.RemoteAction.OnActionListener);
+    method public android.app.RemoteAction clone();
+    method public int describeContents();
+    method public void dump(java.lang.String, java.io.PrintWriter);
+    method public java.lang.CharSequence getContentDescription();
+    method public android.graphics.drawable.Icon getIcon();
+    method public java.lang.CharSequence getTitle();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.RemoteAction> CREATOR;
+  }
+
+  public static abstract interface RemoteAction.OnActionListener {
+    method public abstract void onAction(android.app.RemoteAction);
+  }
+
   public final class RemoteInput implements android.os.Parcelable {
     method public static void addResultsToIntent(android.app.RemoteInput[], android.content.Intent, android.os.Bundle);
     method public int describeContents();
@@ -6224,6 +6246,9 @@
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
     field public static final deprecated java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM";
+    field public static final java.lang.String EXTRA_PROVISIONING_DISCLAIMERS = "android.app.extra.PROVISIONING_DISCLAIMERS";
+    field public static final java.lang.String EXTRA_PROVISIONING_DISCLAIMER_CONTENT = "android.app.extra.PROVISIONING_DISCLAIMER_CONTENT";
+    field public static final java.lang.String EXTRA_PROVISIONING_DISCLAIMER_HEADER = "android.app.extra.PROVISIONING_DISCLAIMER_HEADER";
     field public static final java.lang.String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.PROVISIONING_EMAIL_ADDRESS";
     field public static final java.lang.String EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION = "android.app.extra.PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION";
     field public static final java.lang.String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
@@ -8409,6 +8434,7 @@
     field public static final java.lang.String TELECOM_SERVICE = "telecom";
     field public static final java.lang.String TELEPHONY_SERVICE = "phone";
     field public static final java.lang.String TELEPHONY_SUBSCRIPTION_SERVICE = "telephony_subscription_service";
+    field public static final java.lang.String TEXT_CLASSIFICATION_SERVICE = "textclassification";
     field public static final java.lang.String TEXT_SERVICES_MANAGER_SERVICE = "textservices";
     field public static final java.lang.String TV_INPUT_SERVICE = "tv_input";
     field public static final java.lang.String UI_MODE_SERVICE = "uimode";
@@ -9718,6 +9744,7 @@
   public class LauncherApps {
     ctor public LauncherApps(android.content.Context);
     method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
+    method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent);
     method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
     method public android.graphics.drawable.Drawable getShortcutIconDrawable(android.content.pm.ShortcutInfo, int);
     method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
@@ -9733,6 +9760,8 @@
     method public void startShortcut(java.lang.String, java.lang.String, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
     method public void startShortcut(android.content.pm.ShortcutInfo, android.graphics.Rect, android.os.Bundle);
     method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
+    field public static final java.lang.String ACTION_CONFIRM_PIN_ITEM = "android.content.pm.action.CONFIRM_PIN_ITEM";
+    field public static final java.lang.String EXTRA_PIN_ITEM_REQUEST = "android.content.pm.extra.PIN_ITEM_REQUEST";
   }
 
   public static abstract class LauncherApps.Callback {
@@ -9747,6 +9776,21 @@
     method public void onShortcutsChanged(java.lang.String, java.util.List<android.content.pm.ShortcutInfo>, android.os.UserHandle);
   }
 
+  public static final class LauncherApps.PinItemRequest implements android.os.Parcelable {
+    method public boolean accept(android.os.Bundle);
+    method public boolean accept();
+    method public int describeContents();
+    method public int getRequestType();
+    method public android.content.pm.ShortcutInfo getShortcutInfo();
+    method public boolean isValid();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.content.pm.LauncherApps.PinItemRequest> CREATOR;
+    field public static final int REQUEST_TYPE_SHORTCUT = 1; // 0x1
+  }
+
+  public static abstract class LauncherApps.PinItemRequest.RequestType implements java.lang.annotation.Annotation {
+  }
+
   public static class LauncherApps.ShortcutQuery {
     ctor public LauncherApps.ShortcutQuery();
     method public android.content.pm.LauncherApps.ShortcutQuery setActivity(android.content.ComponentName);
@@ -10314,9 +10358,11 @@
     method public int getMaxShortcutCountPerActivity();
     method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
     method public boolean isRateLimitingActive();
+    method public boolean isRequestPinShortcutSupported();
     method public void removeAllDynamicShortcuts();
     method public void removeDynamicShortcuts(java.util.List<java.lang.String>);
     method public void reportShortcutUsed(java.lang.String);
+    method public boolean requestPinShortcut(android.content.pm.ShortcutInfo, android.content.IntentSender);
     method public boolean setDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
     method public boolean updateShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
   }
@@ -11754,6 +11800,8 @@
     method public static android.graphics.Bitmap createBitmap(android.graphics.Bitmap, int, int, int, int, android.graphics.Matrix, boolean);
     method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config);
     method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config);
+    method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config, boolean);
+    method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config, boolean);
     method public static android.graphics.Bitmap createBitmap(int[], int, int, int, int, android.graphics.Bitmap.Config);
     method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int[], int, int, int, int, android.graphics.Bitmap.Config);
     method public static android.graphics.Bitmap createBitmap(int[], int, int, android.graphics.Bitmap.Config);
@@ -11817,6 +11865,8 @@
     enum_constant public static final android.graphics.Bitmap.Config ALPHA_8;
     enum_constant public static final deprecated android.graphics.Bitmap.Config ARGB_4444;
     enum_constant public static final android.graphics.Bitmap.Config ARGB_8888;
+    enum_constant public static final android.graphics.Bitmap.Config HARDWARE;
+    enum_constant public static final android.graphics.Bitmap.Config RGBA_F16;
     enum_constant public static final android.graphics.Bitmap.Config RGB_565;
   }
 
@@ -12176,6 +12226,7 @@
     method public android.graphics.Bitmap render();
     method public android.graphics.ColorSpace.Renderer showWhitePoint(boolean);
     method public android.graphics.ColorSpace.Renderer size(int);
+    method public android.graphics.ColorSpace.Renderer uniformChromaticityScale(boolean);
   }
 
   public static class ColorSpace.Rgb extends android.graphics.ColorSpace {
@@ -12277,12 +12328,6 @@
     enum_constant public static final android.graphics.Interpolator.Result NORMAL;
   }
 
-  public deprecated class LayerRasterizer extends android.graphics.Rasterizer {
-    ctor public LayerRasterizer();
-    method public void addLayer(android.graphics.Paint, float, float);
-    method public void addLayer(android.graphics.Paint);
-  }
-
   public class LightingColorFilter extends android.graphics.ColorFilter {
     ctor public LightingColorFilter(int, int);
   }
@@ -12444,7 +12489,6 @@
     method public int getOffsetForAdvance(char[], int, int, int, int, boolean, float);
     method public int getOffsetForAdvance(java.lang.CharSequence, int, int, int, int, boolean, float);
     method public android.graphics.PathEffect getPathEffect();
-    method public deprecated android.graphics.Rasterizer getRasterizer();
     method public float getRunAdvance(char[], int, int, int, int, boolean, int);
     method public float getRunAdvance(java.lang.CharSequence, int, int, int, int, boolean, int);
     method public android.graphics.Shader getShader();
@@ -12501,7 +12545,6 @@
     method public void setLinearText(boolean);
     method public android.graphics.MaskFilter setMaskFilter(android.graphics.MaskFilter);
     method public android.graphics.PathEffect setPathEffect(android.graphics.PathEffect);
-    method public deprecated android.graphics.Rasterizer setRasterizer(android.graphics.Rasterizer);
     method public android.graphics.Shader setShader(android.graphics.Shader);
     method public void setShadowLayer(float, float, float, int);
     method public void setStrikeThruText(boolean);
@@ -12719,7 +12762,9 @@
     field public static final deprecated int RGBA_4444 = 7; // 0x7
     field public static final deprecated int RGBA_5551 = 6; // 0x6
     field public static final int RGBA_8888 = 1; // 0x1
+    field public static final int RGBA_F16 = 22; // 0x16
     field public static final int RGBX_8888 = 2; // 0x2
+    field public static final int RGBX_F16 = 23; // 0x17
     field public static final deprecated int RGB_332 = 11; // 0xb
     field public static final int RGB_565 = 4; // 0x4
     field public static final int RGB_888 = 3; // 0x3
@@ -12808,10 +12853,6 @@
     ctor public RadialGradient(float, float, float, int, int, android.graphics.Shader.TileMode);
   }
 
-  public deprecated class Rasterizer {
-    ctor public Rasterizer();
-  }
-
   public final class Rect implements android.os.Parcelable {
     ctor public Rect();
     ctor public Rect(int, int, int, int);
@@ -15279,6 +15320,10 @@
     field public static final int CONTROL = 1; // 0x1
     field public static final int CR = 2; // 0x2
     field public static final int EXTEND = 3; // 0x3
+    field public static final int E_BASE = 13; // 0xd
+    field public static final int E_BASE_GAZ = 14; // 0xe
+    field public static final int E_MODIFIER = 15; // 0xf
+    field public static final int GLUE_AFTER_ZWJ = 16; // 0x10
     field public static final int L = 4; // 0x4
     field public static final int LF = 5; // 0x5
     field public static final int LV = 6; // 0x6
@@ -15289,6 +15334,7 @@
     field public static final int SPACING_MARK = 10; // 0xa
     field public static final int T = 8; // 0x8
     field public static final int V = 9; // 0x9
+    field public static final int ZWJ = 17; // 0x11
   }
 
   public static abstract interface UCharacter.HangulSyllableType {
@@ -15301,6 +15347,9 @@
   }
 
   public static abstract interface UCharacter.JoiningGroup {
+    field public static final int AFRICAN_FEH = 86; // 0x56
+    field public static final int AFRICAN_NOON = 87; // 0x57
+    field public static final int AFRICAN_QAF = 88; // 0x58
     field public static final int AIN = 1; // 0x1
     field public static final int ALAPH = 2; // 0x2
     field public static final int ALEF = 3; // 0x3
@@ -15414,6 +15463,8 @@
     field public static final int CONDITIONAL_JAPANESE_STARTER = 37; // 0x25
     field public static final int CONTINGENT_BREAK = 7; // 0x7
     field public static final int EXCLAMATION = 11; // 0xb
+    field public static final int E_BASE = 40; // 0x28
+    field public static final int E_MODIFIER = 41; // 0x29
     field public static final int GLUE = 12; // 0xc
     field public static final int H2 = 31; // 0x1f
     field public static final int H3 = 32; // 0x20
@@ -15440,6 +15491,7 @@
     field public static final int SURROGATE = 25; // 0x19
     field public static final int UNKNOWN = 0; // 0x0
     field public static final int WORD_JOINER = 30; // 0x1e
+    field public static final int ZWJ = 42; // 0x2a
     field public static final int ZWSPACE = 28; // 0x1c
   }
 
@@ -15473,6 +15525,8 @@
     method public int getID();
     method public static android.icu.lang.UCharacter.UnicodeBlock getInstance(int);
     method public static android.icu.lang.UCharacter.UnicodeBlock of(int);
+    field public static final android.icu.lang.UCharacter.UnicodeBlock ADLAM;
+    field public static final int ADLAM_ID = 263; // 0x107
     field public static final android.icu.lang.UCharacter.UnicodeBlock AEGEAN_NUMBERS;
     field public static final int AEGEAN_NUMBERS_ID = 119; // 0x77
     field public static final android.icu.lang.UCharacter.UnicodeBlock AHOM;
@@ -15521,6 +15575,8 @@
     field public static final int BATAK_ID = 199; // 0xc7
     field public static final android.icu.lang.UCharacter.UnicodeBlock BENGALI;
     field public static final int BENGALI_ID = 16; // 0x10
+    field public static final android.icu.lang.UCharacter.UnicodeBlock BHAIKSUKI;
+    field public static final int BHAIKSUKI_ID = 264; // 0x108
     field public static final android.icu.lang.UCharacter.UnicodeBlock BLOCK_ELEMENTS;
     field public static final int BLOCK_ELEMENTS_ID = 53; // 0x35
     field public static final android.icu.lang.UCharacter.UnicodeBlock BOPOMOFO;
@@ -15610,6 +15666,8 @@
     field public static final int CYRILLIC_EXTENDED_A_ID = 158; // 0x9e
     field public static final android.icu.lang.UCharacter.UnicodeBlock CYRILLIC_EXTENDED_B;
     field public static final int CYRILLIC_EXTENDED_B_ID = 160; // 0xa0
+    field public static final android.icu.lang.UCharacter.UnicodeBlock CYRILLIC_EXTENDED_C;
+    field public static final int CYRILLIC_EXTENDED_C_ID = 265; // 0x109
     field public static final int CYRILLIC_ID = 9; // 0x9
     field public static final android.icu.lang.UCharacter.UnicodeBlock CYRILLIC_SUPPLEMENT;
     field public static final android.icu.lang.UCharacter.UnicodeBlock CYRILLIC_SUPPLEMENTARY;
@@ -15663,6 +15721,8 @@
     field public static final int GEORGIAN_SUPPLEMENT_ID = 135; // 0x87
     field public static final android.icu.lang.UCharacter.UnicodeBlock GLAGOLITIC;
     field public static final int GLAGOLITIC_ID = 136; // 0x88
+    field public static final android.icu.lang.UCharacter.UnicodeBlock GLAGOLITIC_SUPPLEMENT;
+    field public static final int GLAGOLITIC_SUPPLEMENT_ID = 266; // 0x10a
     field public static final android.icu.lang.UCharacter.UnicodeBlock GOTHIC;
     field public static final int GOTHIC_ID = 89; // 0x59
     field public static final android.icu.lang.UCharacter.UnicodeBlock GRANTHA;
@@ -15701,6 +15761,8 @@
     field public static final int HIRAGANA_ID = 62; // 0x3e
     field public static final android.icu.lang.UCharacter.UnicodeBlock IDEOGRAPHIC_DESCRIPTION_CHARACTERS;
     field public static final int IDEOGRAPHIC_DESCRIPTION_CHARACTERS_ID = 60; // 0x3c
+    field public static final android.icu.lang.UCharacter.UnicodeBlock IDEOGRAPHIC_SYMBOLS_AND_PUNCTUATION;
+    field public static final int IDEOGRAPHIC_SYMBOLS_AND_PUNCTUATION_ID = 267; // 0x10b
     field public static final android.icu.lang.UCharacter.UnicodeBlock IMPERIAL_ARAMAIC;
     field public static final int IMPERIAL_ARAMAIC_ID = 186; // 0xba
     field public static final android.icu.lang.UCharacter.UnicodeBlock INSCRIPTIONAL_PAHLAVI;
@@ -15785,6 +15847,8 @@
     field public static final int MANDAIC_ID = 198; // 0xc6
     field public static final android.icu.lang.UCharacter.UnicodeBlock MANICHAEAN;
     field public static final int MANICHAEAN_ID = 234; // 0xea
+    field public static final android.icu.lang.UCharacter.UnicodeBlock MARCHEN;
+    field public static final int MARCHEN_ID = 268; // 0x10c
     field public static final android.icu.lang.UCharacter.UnicodeBlock MATHEMATICAL_ALPHANUMERIC_SYMBOLS;
     field public static final int MATHEMATICAL_ALPHANUMERIC_SYMBOLS_ID = 93; // 0x5d
     field public static final android.icu.lang.UCharacter.UnicodeBlock MATHEMATICAL_OPERATORS;
@@ -15819,6 +15883,8 @@
     field public static final int MODI_ID = 236; // 0xec
     field public static final android.icu.lang.UCharacter.UnicodeBlock MONGOLIAN;
     field public static final int MONGOLIAN_ID = 37; // 0x25
+    field public static final android.icu.lang.UCharacter.UnicodeBlock MONGOLIAN_SUPPLEMENT;
+    field public static final int MONGOLIAN_SUPPLEMENT_ID = 269; // 0x10d
     field public static final android.icu.lang.UCharacter.UnicodeBlock MRO;
     field public static final int MRO_ID = 237; // 0xed
     field public static final android.icu.lang.UCharacter.UnicodeBlock MULTANI;
@@ -15833,6 +15899,8 @@
     field public static final int MYANMAR_ID = 28; // 0x1c
     field public static final android.icu.lang.UCharacter.UnicodeBlock NABATAEAN;
     field public static final int NABATAEAN_ID = 239; // 0xef
+    field public static final android.icu.lang.UCharacter.UnicodeBlock NEWA;
+    field public static final int NEWA_ID = 270; // 0x10e
     field public static final android.icu.lang.UCharacter.UnicodeBlock NEW_TAI_LUE;
     field public static final int NEW_TAI_LUE_ID = 139; // 0x8b
     field public static final android.icu.lang.UCharacter.UnicodeBlock NKO;
@@ -15864,6 +15932,8 @@
     field public static final int ORIYA_ID = 19; // 0x13
     field public static final android.icu.lang.UCharacter.UnicodeBlock ORNAMENTAL_DINGBATS;
     field public static final int ORNAMENTAL_DINGBATS_ID = 242; // 0xf2
+    field public static final android.icu.lang.UCharacter.UnicodeBlock OSAGE;
+    field public static final int OSAGE_ID = 271; // 0x10f
     field public static final android.icu.lang.UCharacter.UnicodeBlock OSMANYA;
     field public static final int OSMANYA_ID = 122; // 0x7a
     field public static final android.icu.lang.UCharacter.UnicodeBlock PAHAWH_HMONG;
@@ -15966,6 +16036,10 @@
     field public static final int TAKRI_ID = 220; // 0xdc
     field public static final android.icu.lang.UCharacter.UnicodeBlock TAMIL;
     field public static final int TAMIL_ID = 20; // 0x14
+    field public static final android.icu.lang.UCharacter.UnicodeBlock TANGUT;
+    field public static final android.icu.lang.UCharacter.UnicodeBlock TANGUT_COMPONENTS;
+    field public static final int TANGUT_COMPONENTS_ID = 273; // 0x111
+    field public static final int TANGUT_ID = 272; // 0x110
     field public static final android.icu.lang.UCharacter.UnicodeBlock TELUGU;
     field public static final int TELUGU_ID = 21; // 0x15
     field public static final android.icu.lang.UCharacter.UnicodeBlock THAANA;
@@ -16012,7 +16086,11 @@
     field public static final int DOUBLE_QUOTE = 16; // 0x10
     field public static final int EXTEND = 9; // 0x9
     field public static final int EXTENDNUMLET = 7; // 0x7
+    field public static final int E_BASE = 17; // 0x11
+    field public static final int E_BASE_GAZ = 18; // 0x12
+    field public static final int E_MODIFIER = 19; // 0x13
     field public static final int FORMAT = 2; // 0x2
+    field public static final int GLUE_AFTER_ZWJ = 20; // 0x14
     field public static final int HEBREW_LETTER = 14; // 0xe
     field public static final int KATAKANA = 3; // 0x3
     field public static final int LF = 10; // 0xa
@@ -16024,6 +16102,7 @@
     field public static final int OTHER = 0; // 0x0
     field public static final int REGIONAL_INDICATOR = 13; // 0xd
     field public static final int SINGLE_QUOTE = 15; // 0xf
+    field public static final int ZWJ = 21; // 0x15
   }
 
   public final class UCharacterCategory implements android.icu.lang.UCharacterEnums.ECharacterCategory {
@@ -16242,6 +16321,7 @@
     method public static final boolean hasScript(int, int);
     method public static final boolean isCased(int);
     method public static final boolean isRightToLeft(int);
+    field public static final int ADLAM = 167; // 0xa7
     field public static final int AFAKA = 147; // 0x93
     field public static final int AHOM = 161; // 0xa1
     field public static final int ANATOLIAN_HIEROGLYPHS = 156; // 0x9c
@@ -16253,6 +16333,7 @@
     field public static final int BASSA_VAH = 134; // 0x86
     field public static final int BATAK = 63; // 0x3f
     field public static final int BENGALI = 4; // 0x4
+    field public static final int BHAIKSUKI = 168; // 0xa8
     field public static final int BLISSYMBOLS = 64; // 0x40
     field public static final int BOOK_PAHLAVI = 124; // 0x7c
     field public static final int BOPOMOFO = 5; // 0x5
@@ -16291,6 +16372,7 @@
     field public static final int HAN = 17; // 0x11
     field public static final int HANGUL = 18; // 0x12
     field public static final int HANUNOO = 43; // 0x2b
+    field public static final int HAN_WITH_BOPOMOFO = 172; // 0xac
     field public static final int HARAPPAN_INDUS = 77; // 0x4d
     field public static final int HATRAN = 162; // 0xa2
     field public static final int HEBREW = 19; // 0x13
@@ -16301,6 +16383,7 @@
     field public static final int INSCRIPTIONAL_PAHLAVI = 122; // 0x7a
     field public static final int INSCRIPTIONAL_PARTHIAN = 125; // 0x7d
     field public static final int INVALID_CODE = -1; // 0xffffffff
+    field public static final int JAMO = 173; // 0xad
     field public static final int JAPANESE = 105; // 0x69
     field public static final int JAVANESE = 78; // 0x4e
     field public static final int JURCHEN = 148; // 0x94
@@ -16334,6 +16417,7 @@
     field public static final int MANDAEAN = 84; // 0x54
     field public static final int MANDAIC = 84; // 0x54
     field public static final int MANICHAEAN = 121; // 0x79
+    field public static final int MARCHEN = 169; // 0xa9
     field public static final int MATHEMATICAL_NOTATION = 128; // 0x80
     field public static final int MAYAN_HIEROGLYPHS = 85; // 0x55
     field public static final int MEITEI_MAYEK = 115; // 0x73
@@ -16350,6 +16434,7 @@
     field public static final int MYANMAR = 28; // 0x1c
     field public static final int NABATAEAN = 143; // 0x8f
     field public static final int NAKHI_GEBA = 132; // 0x84
+    field public static final int NEWA = 170; // 0xaa
     field public static final int NEW_TAI_LUE = 59; // 0x3b
     field public static final int NKO = 87; // 0x57
     field public static final int NUSHU = 150; // 0x96
@@ -16364,6 +16449,7 @@
     field public static final int OL_CHIKI = 109; // 0x6d
     field public static final int ORIYA = 31; // 0x1f
     field public static final int ORKHON = 88; // 0x58
+    field public static final int OSAGE = 171; // 0xab
     field public static final int OSMANYA = 50; // 0x32
     field public static final int PAHAWH_HMONG = 75; // 0x4b
     field public static final int PALMYRENE = 144; // 0x90
@@ -16389,6 +16475,7 @@
     field public static final int SUNDANESE = 113; // 0x71
     field public static final int SYLOTI_NAGRI = 58; // 0x3a
     field public static final int SYMBOLS = 129; // 0x81
+    field public static final int SYMBOLS_EMOJI = 174; // 0xae
     field public static final int SYRIAC = 34; // 0x22
     field public static final int TAGALOG = 42; // 0x2a
     field public static final int TAGBANWA = 45; // 0x2d
@@ -16915,6 +17002,8 @@
     method public static final android.icu.text.DateFormat.BooleanAttribute[] values();
     enum_constant public static final android.icu.text.DateFormat.BooleanAttribute PARSE_ALLOW_NUMERIC;
     enum_constant public static final android.icu.text.DateFormat.BooleanAttribute PARSE_ALLOW_WHITESPACE;
+    enum_constant public static final android.icu.text.DateFormat.BooleanAttribute PARSE_MULTIPLE_PATTERNS_FOR_MATCH;
+    enum_constant public static final android.icu.text.DateFormat.BooleanAttribute PARSE_PARTIAL_LITERAL_MATCH;
   }
 
   public static class DateFormat.Field extends java.text.Format.Field {
@@ -17599,6 +17688,7 @@
     field public static final int PERCENTSTYLE = 2; // 0x2
     field public static final int PLURALCURRENCYSTYLE = 6; // 0x6
     field public static final int SCIENTIFICSTYLE = 3; // 0x3
+    field public static final int STANDARDCURRENCYSTYLE = 9; // 0x9
   }
 
   public static class NumberFormat.Field extends java.text.Format.Field {
@@ -18393,7 +18483,7 @@
     field public static final int AM_PM = 9; // 0x9
     field public static final int APRIL = 3; // 0x3
     field public static final int AUGUST = 7; // 0x7
-    field protected static final int BASE_FIELD_COUNT = 23; // 0x17
+    field protected static final deprecated int BASE_FIELD_COUNT = 23; // 0x17
     field public static final int DATE = 5; // 0x5
     field public static final int DAY_OF_MONTH = 5; // 0x5
     field public static final int DAY_OF_WEEK = 7; // 0x7
@@ -18421,7 +18511,7 @@
     field public static final int MARCH = 2; // 0x2
     field protected static final int MAXIMUM = 3; // 0x3
     field protected static final java.util.Date MAX_DATE;
-    field protected static final int MAX_FIELD_COUNT = 32; // 0x20
+    field protected static final deprecated int MAX_FIELD_COUNT = 32; // 0x20
     field protected static final int MAX_JULIAN = 2130706432; // 0x7f000000
     field protected static final long MAX_MILLIS = 183882168921600000L; // 0x28d47dbbf19b000L
     field public static final int MAY = 4; // 0x4
@@ -18741,6 +18831,7 @@
     field public static final android.icu.util.MeasureUnit CELSIUS;
     field public static final android.icu.util.MeasureUnit CENTILITER;
     field public static final android.icu.util.MeasureUnit CENTIMETER;
+    field public static final android.icu.util.MeasureUnit CENTURY;
     field public static final android.icu.util.MeasureUnit CUBIC_CENTIMETER;
     field public static final android.icu.util.MeasureUnit CUBIC_FOOT;
     field public static final android.icu.util.MeasureUnit CUBIC_INCH;
@@ -18749,6 +18840,7 @@
     field public static final android.icu.util.MeasureUnit CUBIC_MILE;
     field public static final android.icu.util.MeasureUnit CUBIC_YARD;
     field public static final android.icu.util.MeasureUnit CUP;
+    field public static final android.icu.util.MeasureUnit CUP_METRIC;
     field public static final android.icu.util.TimeUnit DAY;
     field public static final android.icu.util.MeasureUnit DECILITER;
     field public static final android.icu.util.MeasureUnit DECIMETER;
@@ -18760,6 +18852,7 @@
     field public static final android.icu.util.MeasureUnit FOOT;
     field public static final android.icu.util.MeasureUnit FURLONG;
     field public static final android.icu.util.MeasureUnit GALLON;
+    field public static final android.icu.util.MeasureUnit GENERIC_TEMPERATURE;
     field public static final android.icu.util.MeasureUnit GIGABIT;
     field public static final android.icu.util.MeasureUnit GIGABYTE;
     field public static final android.icu.util.MeasureUnit GIGAHERTZ;
@@ -18787,8 +18880,10 @@
     field public static final android.icu.util.MeasureUnit KILOMETER_PER_HOUR;
     field public static final android.icu.util.MeasureUnit KILOWATT;
     field public static final android.icu.util.MeasureUnit KILOWATT_HOUR;
+    field public static final android.icu.util.MeasureUnit KNOT;
     field public static final android.icu.util.MeasureUnit LIGHT_YEAR;
     field public static final android.icu.util.MeasureUnit LITER;
+    field public static final android.icu.util.MeasureUnit LITER_PER_100KILOMETERS;
     field public static final android.icu.util.MeasureUnit LITER_PER_KILOMETER;
     field public static final android.icu.util.MeasureUnit LUX;
     field public static final android.icu.util.MeasureUnit MEGABIT;
@@ -18806,6 +18901,7 @@
     field public static final android.icu.util.MeasureUnit MILE;
     field public static final android.icu.util.MeasureUnit MILE_PER_GALLON;
     field public static final android.icu.util.MeasureUnit MILE_PER_HOUR;
+    field public static final android.icu.util.MeasureUnit MILE_SCANDINAVIAN;
     field public static final android.icu.util.MeasureUnit MILLIAMPERE;
     field public static final android.icu.util.MeasureUnit MILLIBAR;
     field public static final android.icu.util.MeasureUnit MILLIGRAM;
@@ -18825,10 +18921,12 @@
     field public static final android.icu.util.MeasureUnit PARSEC;
     field public static final android.icu.util.MeasureUnit PICOMETER;
     field public static final android.icu.util.MeasureUnit PINT;
+    field public static final android.icu.util.MeasureUnit PINT_METRIC;
     field public static final android.icu.util.MeasureUnit POUND;
     field public static final android.icu.util.MeasureUnit POUND_PER_SQUARE_INCH;
     field public static final android.icu.util.MeasureUnit QUART;
     field public static final android.icu.util.MeasureUnit RADIAN;
+    field public static final android.icu.util.MeasureUnit REVOLUTION_ANGLE;
     field public static final android.icu.util.TimeUnit SECOND;
     field public static final android.icu.util.MeasureUnit SQUARE_CENTIMETER;
     field public static final android.icu.util.MeasureUnit SQUARE_FOOT;
@@ -19140,6 +19238,7 @@
     field public static final android.icu.util.VersionInfo UNICODE_6_3;
     field public static final android.icu.util.VersionInfo UNICODE_7_0;
     field public static final android.icu.util.VersionInfo UNICODE_8_0;
+    field public static final android.icu.util.VersionInfo UNICODE_9_0;
   }
 
 }
@@ -22702,6 +22801,7 @@
     method public android.content.ComponentName getServiceComponent();
     method public android.media.session.MediaSession.Token getSessionToken();
     method public boolean isConnected();
+    method public void search(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SearchCallback);
     method public void subscribe(java.lang.String, android.media.browse.MediaBrowser.SubscriptionCallback);
     method public void subscribe(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SubscriptionCallback);
     method public void unsubscribe(java.lang.String);
@@ -22737,6 +22837,12 @@
     field public static final int FLAG_PLAYABLE = 2; // 0x2
   }
 
+  public static abstract class MediaBrowser.SearchCallback {
+    ctor public MediaBrowser.SearchCallback();
+    method public void onError(java.lang.String, android.os.Bundle);
+    method public void onSearchResult(java.lang.String, android.os.Bundle, java.util.List<android.media.browse.MediaBrowser.MediaItem>);
+  }
+
   public static abstract class MediaBrowser.SubscriptionCallback {
     ctor public MediaBrowser.SubscriptionCallback();
     method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>);
@@ -29207,6 +29313,27 @@
     method public abstract android.os.IBinder asBinder();
   }
 
+  public class IncidentManager {
+    method public void reportIncident(android.os.IncidentReportArgs);
+    method public void reportIncident(java.lang.String, byte[]);
+  }
+
+  public final class IncidentReportArgs implements android.os.Parcelable {
+    ctor public IncidentReportArgs();
+    ctor public IncidentReportArgs(android.os.Parcel);
+    method public void addHeader(byte[]);
+    method public void addSection(int);
+    method public boolean containsSection(int);
+    method public int describeContents();
+    method public boolean isAll();
+    method public static android.os.IncidentReportArgs parseSetting(java.lang.String) throws java.lang.IllegalArgumentException;
+    method public void readFromParcel(android.os.Parcel);
+    method public int sectionCount();
+    method public void setAll(boolean);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.os.IncidentReportArgs> CREATOR;
+  }
+
   public final class LocaleList implements android.os.Parcelable {
     ctor public LocaleList(java.util.Locale...);
     method public int describeContents();
@@ -29809,6 +29936,7 @@
     method public deprecated void setUserRestrictions(android.os.Bundle, android.os.UserHandle);
     method public static boolean supportsMultipleUsers();
     field public static final java.lang.String ALLOW_PARENT_PROFILE_APP_LINKING = "allow_parent_profile_app_linking";
+    field public static final java.lang.String DISALLOW_ADD_MANAGED_PROFILE = "no_add_managed_profile";
     field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user";
     field public static final java.lang.String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
     field public static final java.lang.String DISALLOW_APPS_CONTROL = "no_control_apps";
@@ -29833,6 +29961,7 @@
     field public static final java.lang.String DISALLOW_NETWORK_RESET = "no_network_reset";
     field public static final java.lang.String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam";
     field public static final java.lang.String DISALLOW_OUTGOING_CALLS = "no_outgoing_calls";
+    field public static final java.lang.String DISALLOW_REMOVE_MANAGED_PROFILE = "no_remove_managed_profile";
     field public static final java.lang.String DISALLOW_REMOVE_USER = "no_remove_user";
     field public static final java.lang.String DISALLOW_SAFE_BOOT = "no_safe_boot";
     field public static final java.lang.String DISALLOW_SET_USER_ICON = "no_set_user_icon";
@@ -34973,7 +35102,8 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConnected();
     method public void onDisconnected();
-    method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.CancellationSignal, android.service.autofill.FillCallback);
+    method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback);
+    method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.SaveCallback);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
   }
 
@@ -34991,6 +35121,11 @@
     method public android.service.autofill.FillCallback.FillData.Builder setTextField(int, java.lang.String);
   }
 
+  public final class SaveCallback {
+    method public void onFailure(java.lang.CharSequence);
+    method public void onSuccess(int[]);
+  }
+
 }
 
 package android.service.carrier {
@@ -35172,6 +35307,7 @@
     method public abstract void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>);
     method public void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>, android.os.Bundle);
     method public void onLoadItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>);
+    method public void onSearch(java.lang.String, android.os.Bundle, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>);
     method public void setSessionToken(android.media.session.MediaSession.Token);
     field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
   }
@@ -35261,8 +35397,12 @@
     ctor public NotificationAssistantService();
     method public final void adjustNotification(android.service.notification.Adjustment);
     method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>);
+    method public void createNotificationChannel(java.lang.String, android.app.NotificationChannel);
+    method public void deleteNotificationChannel(java.lang.String, java.lang.String);
+    method public java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String);
     method public final android.os.IBinder onBind(android.content.Intent);
     method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+    method public void updateNotificationChannel(java.lang.String, android.app.NotificationChannel);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
   }
 
@@ -37461,6 +37601,7 @@
     field public static final java.lang.String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
     field public static final java.lang.String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
     field public static final java.lang.String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool";
+    field public static final java.lang.String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
     field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
     field public static final java.lang.String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
     field public static final java.lang.String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
@@ -37998,6 +38139,7 @@
     method public java.lang.String getSimOperatorName();
     method public java.lang.String getSimSerialNumber();
     method public int getSimState();
+    method public int getSimState(int);
     method public java.lang.String getSubscriberId();
     method public java.lang.String getVoiceMailAlphaTag();
     method public java.lang.String getVoiceMailNumber();
@@ -38082,7 +38224,11 @@
     field public static final int PHONE_TYPE_NONE = 0; // 0x0
     field public static final int PHONE_TYPE_SIP = 3; // 0x3
     field public static final int SIM_STATE_ABSENT = 1; // 0x1
+    field public static final int SIM_STATE_CARD_IO_ERROR = 8; // 0x8
+    field public static final int SIM_STATE_CARD_RESTRICTED = 9; // 0x9
     field public static final int SIM_STATE_NETWORK_LOCKED = 4; // 0x4
+    field public static final int SIM_STATE_NOT_READY = 6; // 0x6
+    field public static final int SIM_STATE_PERM_DISABLED = 7; // 0x7
     field public static final int SIM_STATE_PIN_REQUIRED = 2; // 0x2
     field public static final int SIM_STATE_PUK_REQUIRED = 3; // 0x3
     field public static final int SIM_STATE_READY = 5; // 0x5
@@ -38849,7 +38995,7 @@
     method public java.lang.CharSequence subSequence(int, int);
   }
 
-  public class AndroidCharacter {
+  public deprecated class AndroidCharacter {
     ctor public AndroidCharacter();
     method public static void getDirectionalities(char[], byte[], int);
     method public static int getEastAsianWidth(char);
@@ -39343,6 +39489,12 @@
     method public java.util.Map<java.lang.String, java.lang.Float> getTypeConfidence();
   }
 
+  public final class TextClassificationManager implements android.text.TextAssistant {
+    method public void addLinks(android.text.Spannable, int);
+    method public java.util.List<android.text.TextLanguage> detectLanguages(java.lang.CharSequence);
+    method public android.text.TextSelection suggestSelection(java.lang.CharSequence, int, int);
+  }
+
   public abstract interface TextDirectionHeuristic {
     method public abstract boolean isRtl(char[], int, int);
     method public abstract boolean isRtl(java.lang.CharSequence, int, int);
@@ -39358,6 +39510,13 @@
     field public static final android.text.TextDirectionHeuristic RTL;
   }
 
+  public final class TextLanguage {
+    ctor public TextLanguage(int, int, java.util.Map<java.lang.String, java.lang.Float>);
+    method public int getEndIndex();
+    method public java.util.Map<java.lang.String, java.lang.Float> getLanguageConfidence();
+    method public int getStartIndex();
+  }
+
   public class TextPaint extends android.graphics.Paint {
     ctor public TextPaint();
     ctor public TextPaint(int);
@@ -40052,12 +40211,6 @@
     method public void writeToParcel(android.os.Parcel, int);
   }
 
-  public class RasterizerSpan extends android.text.style.CharacterStyle implements android.text.style.UpdateAppearance {
-    ctor public RasterizerSpan(android.graphics.Rasterizer);
-    method public android.graphics.Rasterizer getRasterizer();
-    method public void updateDrawState(android.text.TextPaint);
-  }
-
   public class RelativeSizeSpan extends android.text.style.MetricAffectingSpan implements android.text.ParcelableSpan {
     ctor public RelativeSizeSpan(float);
     ctor public RelativeSizeSpan(android.os.Parcel);
@@ -41872,6 +42025,7 @@
     method public android.view.View findNearestTouchable(android.view.ViewGroup, int, int, int, int[]);
     method public final android.view.View findNextFocus(android.view.ViewGroup, android.view.View, int);
     method public android.view.View findNextFocusFromRect(android.view.ViewGroup, android.graphics.Rect, int);
+    method public android.view.View findNextKeyboardNavigationCluster(android.view.ViewGroup, android.view.View, int);
     method public static android.view.FocusFinder getInstance();
   }
 
@@ -43166,6 +43320,7 @@
     method public void addChildrenForAccessibility(java.util.ArrayList<android.view.View>);
     method public void addFocusables(java.util.ArrayList<android.view.View>, int);
     method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
+    method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
     method public void addOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
     method public void addOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
     method public void addTouchables(java.util.ArrayList<android.view.View>);
@@ -43222,7 +43377,8 @@
     method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
     method public boolean dispatchNestedScroll(int, int, int, int, int[]);
     method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public void dispatchProvideStructure(android.view.ViewStructure);
+    method public deprecated void dispatchProvideStructure(android.view.ViewStructure);
+    method public void dispatchProvideStructure(android.view.ViewStructure, int);
     method protected void dispatchRestoreInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSaveInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSetActivated(boolean);
@@ -43319,11 +43475,13 @@
     method public final int getMeasuredWidthAndState();
     method public int getMinimumHeight();
     method public int getMinimumWidth();
+    method public int getNextClusterForwardId();
     method public int getNextFocusDownId();
     method public int getNextFocusForwardId();
     method public int getNextFocusLeftId();
     method public int getNextFocusRightId();
     method public int getNextFocusUpId();
+    method public int getNextSectionForwardId();
     method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
     method public android.view.ViewOutlineProvider getOutlineProvider();
     method public int getOverScrollMode();
@@ -43427,6 +43585,8 @@
     method public boolean isInEditMode();
     method public boolean isInLayout();
     method public boolean isInTouchMode();
+    method public final boolean isKeyboardNavigationCluster();
+    method public final boolean isKeyboardNavigationSection();
     method public boolean isLaidOut();
     method public boolean isLayoutDirectionResolved();
     method public boolean isLayoutRequested();
@@ -43449,6 +43609,7 @@
     method public boolean isVerticalFadingEdgeEnabled();
     method public boolean isVerticalScrollBarEnabled();
     method public void jumpDrawablesToCurrentState();
+    method public android.view.View keyboardNavigationClusterSearch(int);
     method public void layout(int, int, int, int);
     method public final void measure(int, int);
     method protected static int[] mergeDrawableStates(int[], int[]);
@@ -43489,8 +43650,10 @@
     method protected void onMeasure(int, int);
     method protected void onOverScrolled(int, int, boolean, boolean);
     method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public void onProvideStructure(android.view.ViewStructure);
-    method public void onProvideVirtualStructure(android.view.ViewStructure);
+    method public deprecated void onProvideStructure(android.view.ViewStructure);
+    method public void onProvideStructure(android.view.ViewStructure, int);
+    method public deprecated void onProvideVirtualStructure(android.view.ViewStructure);
+    method public void onProvideVirtualStructure(android.view.ViewStructure, int);
     method public android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int);
     method protected void onRestoreInstanceState(android.os.Parcelable);
     method public void onRtlPropertiesChanged(int);
@@ -43593,6 +43756,8 @@
     method public void setId(int);
     method public void setImportantForAccessibility(int);
     method public void setKeepScreenOn(boolean);
+    method public void setKeyboardNavigationCluster(boolean);
+    method public void setKeyboardNavigationSection(boolean);
     method public void setLabelFor(int);
     method public void setLayerPaint(android.graphics.Paint);
     method public void setLayerType(int, android.graphics.Paint);
@@ -43604,11 +43769,13 @@
     method public void setMinimumHeight(int);
     method public void setMinimumWidth(int);
     method public void setNestedScrollingEnabled(boolean);
+    method public void setNextClusterForwardId(int);
     method public void setNextFocusDownId(int);
     method public void setNextFocusForwardId(int);
     method public void setNextFocusLeftId(int);
     method public void setNextFocusRightId(int);
     method public void setNextFocusUpId(int);
+    method public void setNextSectionForwardId(int);
     method public void setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener);
     method public void setOnClickListener(android.view.View.OnClickListener);
     method public void setOnContextClickListener(android.view.View.OnContextClickListener);
@@ -43692,6 +43859,8 @@
     field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
     field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
     field public static final android.util.Property<android.view.View, java.lang.Float> ALPHA;
+    field public static final int ASSIST_FLAG_NON_SANITIZED_TEXT = 2; // 0x2
+    field public static final int ASSIST_FLAG_SANITIZED_TEXT = 1; // 0x1
     field public static final int DRAG_FLAG_GLOBAL = 256; // 0x100
     field public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 64; // 0x40
     field public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 128; // 0x80
@@ -44092,6 +44261,7 @@
     method protected deprecated boolean isChildrenDrawnWithCacheEnabled();
     method public boolean isMotionEventSplittingEnabled();
     method public boolean isTransitionGroup();
+    method public android.view.View keyboardNavigationClusterSearch(android.view.View, int);
     method public final void layout(int, int, int, int);
     method protected void measureChild(android.view.View, int, int);
     method protected void measureChildWithMargins(android.view.View, int, int, int, int);
@@ -44254,6 +44424,7 @@
     method public abstract boolean isLayoutRequested();
     method public abstract boolean isTextAlignmentResolved();
     method public abstract boolean isTextDirectionResolved();
+    method public abstract android.view.View keyboardNavigationClusterSearch(android.view.View, int);
     method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
     method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
     method public abstract boolean onNestedPreFling(android.view.View, float, float);
@@ -60172,6 +60343,10 @@
     ctor public Locale(java.lang.String, java.lang.String);
     ctor public Locale(java.lang.String);
     method public java.lang.Object clone();
+    method public static java.util.List<java.util.Locale> filter(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.util.Locale>, java.util.Locale.FilteringMode);
+    method public static java.util.List<java.util.Locale> filter(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.util.Locale>);
+    method public static java.util.List<java.lang.String> filterTags(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.lang.String>, java.util.Locale.FilteringMode);
+    method public static java.util.List<java.lang.String> filterTags(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.lang.String>);
     method public static java.util.Locale forLanguageTag(java.lang.String);
     method public static java.util.Locale[] getAvailableLocales();
     method public java.lang.String getCountry();
@@ -60200,6 +60375,8 @@
     method public java.lang.String getUnicodeLocaleType(java.lang.String);
     method public java.lang.String getVariant();
     method public boolean hasExtensions();
+    method public static java.util.Locale lookup(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.util.Locale>);
+    method public static java.lang.String lookupTag(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.lang.String>);
     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();
@@ -60255,6 +60432,28 @@
     enum_constant public static final java.util.Locale.Category FORMAT;
   }
 
+  public static final class Locale.FilteringMode extends java.lang.Enum {
+    method public static java.util.Locale.FilteringMode valueOf(java.lang.String);
+    method public static final java.util.Locale.FilteringMode[] values();
+    enum_constant public static final java.util.Locale.FilteringMode AUTOSELECT_FILTERING;
+    enum_constant public static final java.util.Locale.FilteringMode EXTENDED_FILTERING;
+    enum_constant public static final java.util.Locale.FilteringMode IGNORE_EXTENDED_RANGES;
+    enum_constant public static final java.util.Locale.FilteringMode MAP_EXTENDED_RANGES;
+    enum_constant public static final java.util.Locale.FilteringMode REJECT_EXTENDED_RANGES;
+  }
+
+  public static final class Locale.LanguageRange {
+    ctor public Locale.LanguageRange(java.lang.String);
+    ctor public Locale.LanguageRange(java.lang.String, double);
+    method public java.lang.String getRange();
+    method public double getWeight();
+    method public static java.util.List<java.util.Locale.LanguageRange> mapEquivalents(java.util.List<java.util.Locale.LanguageRange>, java.util.Map<java.lang.String, java.util.List<java.lang.String>>);
+    method public static java.util.List<java.util.Locale.LanguageRange> parse(java.lang.String);
+    method public static java.util.List<java.util.Locale.LanguageRange> parse(java.lang.String, java.util.Map<java.lang.String, java.util.List<java.lang.String>>);
+    field public static final double MAX_WEIGHT = 1.0;
+    field public static final double MIN_WEIGHT = 0.0;
+  }
+
   public class LongSummaryStatistics implements java.util.function.IntConsumer java.util.function.LongConsumer {
     ctor public LongSummaryStatistics();
     method public void accept(int);
@@ -61538,31 +61737,31 @@
     ctor public CopyOnWriteArrayList();
     ctor public CopyOnWriteArrayList(java.util.Collection<? extends E>);
     ctor public CopyOnWriteArrayList(E[]);
-    method public synchronized boolean add(E);
-    method public synchronized void add(int, E);
-    method public synchronized boolean addAll(java.util.Collection<? extends E>);
-    method public synchronized boolean addAll(int, java.util.Collection<? extends E>);
-    method public synchronized int addAllAbsent(java.util.Collection<? extends E>);
-    method public synchronized boolean addIfAbsent(E);
-    method public synchronized void clear();
+    method public boolean add(E);
+    method public void add(int, E);
+    method public boolean addAll(java.util.Collection<? extends E>);
+    method public boolean addAll(int, java.util.Collection<? extends E>);
+    method public int addAllAbsent(java.util.Collection<? extends E>);
+    method public boolean addIfAbsent(E);
+    method public void clear();
     method public java.lang.Object clone();
     method public boolean contains(java.lang.Object);
     method public boolean containsAll(java.util.Collection<?>);
     method public void forEach(java.util.function.Consumer<? super E>);
     method public E get(int);
-    method public int indexOf(E, int);
     method public int indexOf(java.lang.Object);
+    method public int indexOf(E, int);
     method public boolean isEmpty();
     method public java.util.Iterator<E> iterator();
-    method public int lastIndexOf(E, int);
     method public int lastIndexOf(java.lang.Object);
-    method public java.util.ListIterator<E> listIterator(int);
+    method public int lastIndexOf(E, int);
     method public java.util.ListIterator<E> listIterator();
-    method public synchronized E remove(int);
-    method public synchronized boolean remove(java.lang.Object);
-    method public synchronized boolean removeAll(java.util.Collection<?>);
-    method public synchronized boolean retainAll(java.util.Collection<?>);
-    method public synchronized E set(int, E);
+    method public java.util.ListIterator<E> listIterator(int);
+    method public E remove(int);
+    method public boolean remove(java.lang.Object);
+    method public boolean removeAll(java.util.Collection<?>);
+    method public boolean retainAll(java.util.Collection<?>);
+    method public E set(int, E);
     method public int size();
     method public java.util.List<E> subList(int, int);
     method public java.lang.Object[] toArray();
diff --git a/api/test-removed.txt b/api/test-removed.txt
index 683a695..10e6eb5 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -78,10 +78,25 @@
     enum_constant public static final android.graphics.AvoidXfermode.Mode TARGET;
   }
 
+  public deprecated class LayerRasterizer extends android.graphics.Rasterizer {
+    ctor public LayerRasterizer();
+    method public void addLayer(android.graphics.Paint, float, float);
+    method public void addLayer(android.graphics.Paint);
+  }
+
+  public class Paint {
+    method public deprecated android.graphics.Rasterizer getRasterizer();
+    method public deprecated android.graphics.Rasterizer setRasterizer(android.graphics.Rasterizer);
+  }
+
   public deprecated class PixelXorXfermode extends android.graphics.Xfermode {
     ctor public PixelXorXfermode(int);
   }
 
+  public class Rasterizer {
+    ctor public Rasterizer();
+  }
+
 }
 
 package android.location {
@@ -393,6 +408,15 @@
 
 }
 
+package android.text.style {
+
+  public class RasterizerSpan extends android.text.style.CharacterStyle implements android.text.style.UpdateAppearance {
+    ctor public RasterizerSpan(android.graphics.Rasterizer);
+    method public android.graphics.Rasterizer getRasterizer();
+  }
+
+}
+
 package android.util {
 
   public deprecated class FloatMath {
diff --git a/cmds/bootanimation/bootanimation_main.cpp b/cmds/bootanimation/bootanimation_main.cpp
index 48a34e7..dca7ea6 100644
--- a/cmds/bootanimation/bootanimation_main.cpp
+++ b/cmds/bootanimation/bootanimation_main.cpp
@@ -37,6 +37,10 @@
     char value[PROPERTY_VALUE_MAX];
     property_get("debug.sf.nobootanimation", value, "0");
     int noBootAnimation = atoi(value);
+    if (!noBootAnimation) {
+        property_get("ro.boot.quiescent", value, "0");
+        noBootAnimation = atoi(value);
+    }
     ALOGI_IF(noBootAnimation,  "boot animation disabled");
     if (!noBootAnimation) {
 
@@ -47,7 +51,6 @@
         sp<BootAnimation> boot = new BootAnimation();
 
         IPCThreadState::self()->joinThreadPool();
-
     }
     return 0;
 }
diff --git a/cmds/incident/Android.mk b/cmds/incident/Android.mk
new file mode 100644
index 0000000..e1c9b93
--- /dev/null
+++ b/cmds/incident/Android.mk
@@ -0,0 +1,48 @@
+# 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 := \
+        main.cpp
+
+LOCAL_MODULE := incident
+
+LOCAL_SHARED_LIBRARIES := \
+        libbase \
+        libbinder \
+        libcutils \
+        liblog \
+        libutils \
+        libincident
+
+LOCAL_CFLAGS += \
+        -Wall -Werror -Wno-missing-field-initializers -Wno-unused-variable -Wunused-parameter
+
+LOCAL_MODULE_CLASS := EXECUTABLES
+gen_src_dir := $(local-generated-sources-dir)
+
+gen := $(gen_src_dir)/incident_sections.cpp
+$(gen): $(HOST_OUT_EXECUTABLES)/incident-section-gen
+$(gen): PRIVATE_CUSTOM_TOOL = \
+    $(HOST_OUT_EXECUTABLES)/incident-section-gen > $@
+$(gen): $(HOST_OUT_EXECUTABLES)/incident-section-gen
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(gen)
+
+gen_src_dir:=
+gen:=
+
+include $(BUILD_EXECUTABLE)
diff --git a/cmds/incident/incident_sections.h b/cmds/incident/incident_sections.h
new file mode 100644
index 0000000..1972088
--- /dev/null
+++ b/cmds/incident/incident_sections.h
@@ -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.
+ */
+
+#ifndef INCIDENT_SECTIONS_H
+#define INCIDENT_SECTIONS_H
+
+struct IncidentSection
+{
+    int id;
+    char const* name;
+};
+
+extern IncidentSection const INCIDENT_SECTIONS[];
+extern const int INCIDENT_SECTION_COUNT;
+
+#endif // INCIDENT_SECTIONS_H
diff --git a/cmds/incident/main.cpp b/cmds/incident/main.cpp
new file mode 100644
index 0000000..91b7c22
--- /dev/null
+++ b/cmds/incident/main.cpp
@@ -0,0 +1,236 @@
+/*
+ * 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_TAG "incident"
+
+#include "incident_sections.h"
+
+#include <android/os/BnIncidentReportStatusListener.h>
+#include <android/os/IIncidentManager.h>
+#include <android/os/IncidentReportArgs.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <utils/Looper.h>
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+using namespace android;
+using namespace android::base;
+using namespace android::binder;
+using namespace android::os;
+
+// ================================================================================
+class StatusListener : public BnIncidentReportStatusListener {
+public:
+    StatusListener();
+    virtual ~StatusListener();
+
+    virtual Status onReportStarted();
+    virtual Status onReportSectionStatus(int32_t section, int32_t status);
+    virtual Status onReportServiceStatus(const String16& service, int32_t status);
+    virtual Status onReportFinished();
+    virtual Status onReportFailed();
+};
+
+StatusListener::StatusListener()
+{
+}
+
+StatusListener::~StatusListener()
+{
+}
+
+Status
+StatusListener::onReportStarted()
+{
+    return Status::ok();
+}
+
+Status
+StatusListener::onReportSectionStatus(int32_t section, int32_t status)
+{
+    fprintf(stderr, "section %d status %d\n", section, status);
+    return Status::ok();
+}
+
+Status
+StatusListener::onReportServiceStatus(const String16& service, int32_t status)
+{
+    fprintf(stderr, "service '%s' status %d\n", String8(service).string(), status);
+    return Status::ok();
+}
+
+Status
+StatusListener::onReportFinished()
+{
+    fprintf(stderr, "done\n");
+    exit(0);
+    return Status::ok();
+}
+
+Status
+StatusListener::onReportFailed()
+{
+    fprintf(stderr, "failed\n");
+    exit(1);
+    return Status::ok();
+}
+
+// ================================================================================
+static IncidentSection const*
+find_section(const char* name)
+{
+    size_t low = 0;
+    size_t high = INCIDENT_SECTION_COUNT - 1;
+
+    while (low <= high) {
+        size_t mid = (low + high) >> 1;
+        IncidentSection const* section = INCIDENT_SECTIONS + mid;
+
+        int cmp = strcmp(section->name, name);
+        if (cmp < 0) {
+            low = mid + 1;
+        } else if (cmp > 0) {
+            high = mid - 1;
+        } else {
+            return section;
+        }
+    }
+    return NULL;
+}
+
+// ================================================================================
+static void
+usage(FILE* out)
+{
+    fprintf(out, "usage: incident OPTIONS [SECTION...]\n");
+    fprintf(out, "\n");
+    fprintf(out, "Takes an incident report.\n");
+    fprintf(out, "\n");
+    fprintf(out, "OPTIONS\n");
+    fprintf(out, "  -b           (default) print the report to stdout (in proto format)\n");
+    fprintf(out, "  -d           send the report into dropbox\n");
+    fprintf(out, "\n");
+    fprintf(out, "  SECTION     the field numbers of the incident report fields to include\n");
+    fprintf(out, "\n");
+}
+
+int
+main(int argc, char** argv)
+{
+    Status status;
+    IncidentReportArgs args;
+    enum { DEST_DROPBOX, DEST_STDOUT } destination = DEST_STDOUT;
+
+    // Parse the args
+    int opt;
+    while ((opt = getopt(argc, argv, "bhd")) != -1) {
+        switch (opt) {
+            case 'b':
+                destination = DEST_STDOUT;
+                break;
+            case 'h':
+                usage(stdout);
+                return 0;
+            case 'd':
+                destination = DEST_DROPBOX;
+                break;
+            default:
+                usage(stderr);
+                return 1;
+        }
+    }
+
+    if (optind == argc) {
+        args.setAll(true);
+    } else {
+        for (int i=optind; i<argc; i++) {
+            const char* arg = argv[i];
+            char* end;
+            if (arg[0] != '\0') {
+                int section = strtol(arg, &end, 0);
+                if (*end == '\0') {
+                    args.addSection(section);
+                } else {
+                    IncidentSection const* ic = find_section(arg);
+                    if (ic == NULL) {
+                        fprintf(stderr, "Invalid section: %s\n", arg);
+                        return 1;
+                    }
+                    args.addSection(ic->id);
+                }
+            }
+        }
+    }
+
+
+
+    // Start the thread pool.
+    sp<ProcessState> ps(ProcessState::self());
+    ps->startThreadPool();
+    ps->giveThreadPoolName();
+
+    // Look up the service
+    sp<IIncidentManager> service = interface_cast<IIncidentManager>(
+            defaultServiceManager()->getService(android::String16("incident")));
+    if (service == NULL) {
+        fprintf(stderr, "Couldn't look up the incident service\n");
+        return 1;
+    }
+
+    // Construct the stream
+    int fds[2];
+    pipe(fds);
+
+    unique_fd readEnd(fds[0]);
+    unique_fd writeEnd(fds[1]);
+
+    if (destination == DEST_STDOUT) {
+        // Call into the service
+        sp<StatusListener> listener(new StatusListener());
+        status = service->reportIncidentToStream(args, listener, writeEnd);
+
+        if (!status.isOk()) {
+            fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
+        }
+
+        // Wait for the result and print out the data they send.
+        //IPCThreadState::self()->joinThreadPool();
+
+        while (true) {
+            int amt = splice(fds[0], NULL, STDOUT_FILENO, NULL, 4096, 0);
+            fprintf(stderr, "spliced %d bytes\n", amt);
+            if (amt < 0) {
+                return errno;
+            } else if (amt == 0) {
+                return 0;
+            }
+        }
+    } else {
+        status = service->reportIncident(args);
+        if (!status.isOk()) {
+            fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+}
diff --git a/cmds/incidentd/Android.mk b/cmds/incidentd/Android.mk
new file mode 100644
index 0000000..bacf672
--- /dev/null
+++ b/cmds/incidentd/Android.mk
@@ -0,0 +1,56 @@
+# 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 := incidentd
+
+LOCAL_SRC_FILES := \
+        src/FdBuffer.cpp \
+        src/IncidentService.cpp \
+        src/Reporter.cpp \
+        src/Section.cpp \
+        src/main.cpp \
+        src/protobuf.cpp \
+        src/report_directory.cpp \
+        src/section_list.cpp
+
+LOCAL_CFLAGS += \
+        -Wall -Werror -Wno-missing-field-initializers -Wno-unused-variable -Wunused-parameter
+
+ifeq (debug,)
+    LOCAL_CFLAGS += \
+            -g -O0
+else
+    # optimize for size (protobuf glop can get big)
+    LOCAL_CFLAGS += \
+            -Os
+endif
+
+LOCAL_SHARED_LIBRARIES := \
+        libbase \
+        libbinder \
+        libcutils \
+        libincident \
+        liblog \
+        libselinux \
+        libservices \
+        libutils
+
+ifeq (BUILD_WITH_INCIDENTD_RC,true)
+LOCAL_INIT_RC := incidentd.rc
+endif
+
+include $(BUILD_EXECUTABLE)
diff --git a/cmds/incidentd/incidentd.rc b/cmds/incidentd/incidentd.rc
new file mode 100644
index 0000000..d11e3cf
--- /dev/null
+++ b/cmds/incidentd/incidentd.rc
@@ -0,0 +1,16 @@
+# 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.
+
+#service incidentd /system/bin/incidentd
+#    class main
diff --git a/cmds/incidentd/src/FdBuffer.cpp b/cmds/incidentd/src/FdBuffer.cpp
new file mode 100644
index 0000000..527d7ee
--- /dev/null
+++ b/cmds/incidentd/src/FdBuffer.cpp
@@ -0,0 +1,129 @@
+/*
+ * 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_TAG "incidentd"
+
+#include "FdBuffer.h"
+
+#include <cutils/log.h>
+#include <utils/SystemClock.h>
+
+#include <fcntl.h>
+#include <poll.h>
+#include <unistd.h>
+
+const ssize_t BUFFER_SIZE = 16 * 1024;
+const ssize_t MAX_BUFFER_COUNT = 256; // 4 MB max
+
+
+FdBuffer::FdBuffer()
+    :mBuffers(),
+     mStartTime(-1),
+     mFinishTime(-1),
+     mCurrentWritten(-1),
+     mTimedOut(false),
+     mTruncated(false)
+{
+}
+
+FdBuffer::~FdBuffer()
+{
+    const int N = mBuffers.size();
+    for (int i=0; i<N; i++) {
+        uint8_t* buf = mBuffers[i];
+        free(buf);
+    }
+}
+
+status_t
+FdBuffer::read(int fd, int64_t timeout)
+{
+    struct pollfd pfds = {
+        .fd = fd,
+        .events = POLLIN
+    };
+    mStartTime = uptimeMillis();
+
+    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
+
+    uint8_t* buf = NULL;
+    while (true) {
+        if (mCurrentWritten >= BUFFER_SIZE || mCurrentWritten < 0) {
+            if (mBuffers.size() == MAX_BUFFER_COUNT) {
+                mTruncated = true;
+                break;
+            }
+            buf = (uint8_t*)malloc(BUFFER_SIZE);
+            if (buf == NULL) {
+                return NO_MEMORY;
+            }
+            mBuffers.push_back(buf);
+            mCurrentWritten = 0;
+        }
+
+        int64_t remainingTime = (mStartTime + timeout) - uptimeMillis();
+        if (remainingTime <= 0) {
+            mTimedOut = true;
+            break;
+        }
+
+        int count = poll(&pfds, 1, remainingTime);
+        if (count == 0) {
+            mTimedOut = true;
+            break;
+        } else if (count < 0) {
+            return -errno;
+        } else {
+            if ((pfds.revents & POLLERR) != 0) {
+                return errno != 0 ? -errno : UNKNOWN_ERROR;
+            } else {
+                ssize_t amt = ::read(fd, buf + mCurrentWritten, BUFFER_SIZE - mCurrentWritten);
+                if (amt < 0) {
+                    if (errno == EAGAIN || errno == EWOULDBLOCK) {
+                        continue;
+                    } else {
+                        return -errno;
+                    }
+                } else if (amt == 0) {
+                    break;
+                }
+                mCurrentWritten += amt;
+            }
+        }
+    }
+
+    mFinishTime = uptimeMillis();
+    return NO_ERROR;
+}
+
+size_t
+FdBuffer::size()
+{
+    return ((mBuffers.size() - 1) * BUFFER_SIZE) + mCurrentWritten;
+}
+
+status_t
+FdBuffer::write(ReportRequestSet* reporter)
+{
+    const int N = mBuffers.size() - 1;
+    for (int i=0; i<N; i++) {
+        reporter->write(mBuffers[i], BUFFER_SIZE);
+    }
+    reporter->write(mBuffers[N], mCurrentWritten);
+    return NO_ERROR;
+}
+
+
diff --git a/cmds/incidentd/src/FdBuffer.h b/cmds/incidentd/src/FdBuffer.h
new file mode 100644
index 0000000..e12374f
--- /dev/null
+++ b/cmds/incidentd/src/FdBuffer.h
@@ -0,0 +1,86 @@
+/*
+ * 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 FD_BUFFER_H
+#define FD_BUFFER_H
+
+#include "Reporter.h"
+
+#include <utils/Errors.h>
+
+#include <set>
+#include <vector>
+
+using namespace android;
+using namespace std;
+
+/**
+ * Reads a file into a buffer, and then writes that data to an FdSet.
+ */
+class FdBuffer
+{
+public:
+    FdBuffer();
+    ~FdBuffer();
+
+    /**
+     * Read the data until the timeout is hit or we hit eof.
+     * Returns NO_ERROR if there were no errors or if we timed out.
+     * Will mark the file O_NONBLOCK.
+     */
+    status_t read(int fd, int64_t timeoutMs);
+
+    /**
+     * Whether we timed out.
+     */
+    bool timedOut() { return mTimedOut; }
+
+    /**
+     * If more than 4 MB is read, we truncate the data and return success.
+     * Downstream tools must handle truncated incident reports as best as possible
+     * anyway because they could be cut off for a lot of reasons and it's best
+     * to get as much useful information out of the system as possible. If this
+     * happens, truncated() will return true so it can be marked. If the data is
+     * exactly 4 MB, truncated is still set. Sorry.
+     */
+    bool truncated() { return mTruncated; }
+
+    /**
+     * How much data was read.
+     */
+    size_t size();
+
+    /**
+     * Write the data that we recorded to the fd given.
+     */
+    status_t write(ReportRequestSet* requests);
+
+    /**
+     * How long the read took in milliseconds.
+     */
+    int64_t durationMs() { return mFinishTime - mStartTime; }
+
+private:
+    vector<uint8_t*> mBuffers;
+    int64_t mStartTime;
+    int64_t mFinishTime;
+    ssize_t mCurrentWritten;
+    bool mTimedOut;
+    bool mTruncated;
+};
+
+
+#endif // FD_BUFFER_H
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp
new file mode 100644
index 0000000..7c6789e
--- /dev/null
+++ b/cmds/incidentd/src/IncidentService.cpp
@@ -0,0 +1,244 @@
+/*
+ * 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_TAG "incidentd"
+
+#include "IncidentService.h"
+
+#include "Reporter.h"
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <cutils/log.h>
+#include <private/android_filesystem_config.h>
+#include <utils/Looper.h>
+
+#include <unistd.h>
+
+using namespace android;
+
+enum {
+    WHAT_RUN_REPORT = 1,
+    WHAT_SEND_BACKLOG_TO_DROPBOX = 2
+};
+
+//#define DEFAULT_BACKLOG_DELAY_NS (1000000000LL * 60 * 5)
+#define DEFAULT_BACKLOG_DELAY_NS (1000000000LL)
+
+// ================================================================================
+String16 const DUMP_PERMISSION("android.permission.DUMP");
+String16 const USAGE_STATS_PERMISSION("android.permission.PACKAGE_USAGE_STATS");
+
+static Status
+checkIncidentPermissions()
+{
+    if (!checkCallingPermission(DUMP_PERMISSION)) {
+        ALOGW("Calling pid %d and uid %d does not have permission: android.permission.DUMP",
+                IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid());
+        return Status::fromExceptionCode(Status::EX_SECURITY,
+                "Calling process does not have permission: android.permission.DUMP");
+    }
+    if (!checkCallingPermission(USAGE_STATS_PERMISSION)) {
+        ALOGW("Calling pid %d and uid %d does not have permission: android.permission.USAGE_STATS",
+                IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid());
+        return Status::fromExceptionCode(Status::EX_SECURITY,
+                "Calling process does not have permission: android.permission.USAGE_STATS");
+    }
+    return Status::ok();
+}
+
+
+// ================================================================================
+ReportRequestQueue::ReportRequestQueue()
+{
+}
+
+ReportRequestQueue::~ReportRequestQueue()
+{
+}
+
+void
+ReportRequestQueue::addRequest(const sp<ReportRequest>& request) 
+{
+    unique_lock<mutex> lock(mLock);
+    mQueue.push_back(request);
+}
+
+sp<ReportRequest>
+ReportRequestQueue::getNextRequest()
+{
+    unique_lock<mutex> lock(mLock);
+    if (mQueue.empty()) {
+        return NULL;
+    } else {
+        sp<ReportRequest> front(mQueue.front());
+        mQueue.pop_front();
+        return front;
+    }
+}
+
+
+// ================================================================================
+ReportHandler::ReportHandler(const sp<Looper>& handlerLooper, const sp<ReportRequestQueue>& queue)
+    :mBacklogDelay(DEFAULT_BACKLOG_DELAY_NS),
+     mHandlerLooper(handlerLooper),
+     mQueue(queue)
+{
+}
+
+ReportHandler::~ReportHandler()
+{
+}
+
+void
+ReportHandler::handleMessage(const Message& message)
+{
+    switch (message.what) {
+        case WHAT_RUN_REPORT:
+            run_report();
+            break;
+        case WHAT_SEND_BACKLOG_TO_DROPBOX:
+            send_backlog_to_dropbox();
+            break;
+    }
+}
+
+void
+ReportHandler::scheduleRunReport(const sp<ReportRequest>& request)
+{
+    mQueue->addRequest(request);
+    mHandlerLooper->removeMessages(this, WHAT_RUN_REPORT);
+    mHandlerLooper->sendMessage(this, Message(WHAT_RUN_REPORT));
+}
+
+void
+ReportHandler::scheduleSendBacklogToDropbox()
+{
+    unique_lock<mutex> lock(mLock);
+    mBacklogDelay = DEFAULT_BACKLOG_DELAY_NS;
+    schedule_send_backlog_to_dropbox_locked();
+}
+
+void
+ReportHandler::schedule_send_backlog_to_dropbox_locked()
+{
+    mHandlerLooper->removeMessages(this, WHAT_SEND_BACKLOG_TO_DROPBOX);
+    mHandlerLooper->sendMessageDelayed(mBacklogDelay, this,
+            Message(WHAT_SEND_BACKLOG_TO_DROPBOX));
+}
+
+void
+ReportHandler::run_report()
+{
+    sp<Reporter> reporter = new Reporter();
+
+    // Merge all of the requests into one that has all of the
+    // requested fields.
+    while (true) {
+        sp<ReportRequest> request = mQueue->getNextRequest();
+        if (request == NULL) {
+            break;
+        }
+        reporter->batch.add(request);
+        reporter->args.merge(request->args);
+    }
+
+    // Take the report, which might take a while. More requests might queue
+    // up while we're doing this, and we'll handle them in their next batch.
+    // TODO: We should further rate-limit the reports to no more than N per time-period.
+    Reporter::run_report_status_t reportStatus = reporter->runReport();
+    if (reportStatus == Reporter::REPORT_NEEDS_DROPBOX) {
+        unique_lock<mutex> lock(mLock);
+        schedule_send_backlog_to_dropbox_locked();
+    }
+}
+
+void
+ReportHandler::send_backlog_to_dropbox()
+{
+    if (Reporter::upload_backlog() == Reporter::REPORT_NEEDS_DROPBOX) {
+        // There was a failure. Exponential backoff.
+        unique_lock<mutex> lock(mLock);
+        mBacklogDelay *= 2;
+        ALOGI("Error sending to dropbox. Trying again in %lld minutes",
+                (mBacklogDelay / (1000000000LL * 60)));
+        schedule_send_backlog_to_dropbox_locked();
+    } else {
+        mBacklogDelay = DEFAULT_BACKLOG_DELAY_NS;
+    }
+}
+
+// ================================================================================
+IncidentService::IncidentService(const sp<Looper>& handlerLooper)
+    :mQueue(new ReportRequestQueue())
+{
+    mHandler = new ReportHandler(handlerLooper, mQueue);
+}
+
+IncidentService::~IncidentService()
+{
+}
+
+Status
+IncidentService::reportIncident(const IncidentReportArgs& args)
+{
+    ALOGI("reportIncident");
+
+    Status status = checkIncidentPermissions();
+    if (!status.isOk()) {
+        return status;
+    }
+
+    mHandler->scheduleRunReport(new ReportRequest(args, NULL, -1));
+
+    return Status::ok();
+}
+
+Status
+IncidentService::reportIncidentToStream(const IncidentReportArgs& args,
+            const sp<IIncidentReportStatusListener>& listener, const unique_fd& stream)
+{
+    ALOGI("reportIncidentToStream");
+
+    Status status = checkIncidentPermissions();
+    if (!status.isOk()) {
+        return status;
+    }
+
+    int fd = dup(stream.get());
+    if (fd < 0) {
+        return Status::fromStatusT(-errno);
+    }
+
+    mHandler->scheduleRunReport(new ReportRequest(args, listener, fd));
+
+    return Status::ok();
+}
+
+Status
+IncidentService::systemRunning()
+{
+    if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
+        return Status::fromExceptionCode(Status::EX_SECURITY,
+                "Only system uid can call systemRunning");
+    }
+    
+    // When system_server is up and running, schedule the dropbox task to run.
+    mHandler->scheduleSendBacklogToDropbox();
+
+    return Status::ok();
+}
+
diff --git a/cmds/incidentd/src/IncidentService.h b/cmds/incidentd/src/IncidentService.h
new file mode 100644
index 0000000..d6f33df
--- /dev/null
+++ b/cmds/incidentd/src/IncidentService.h
@@ -0,0 +1,112 @@
+/*
+ * 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 INCIDENT_SERVICE_H
+#define INCIDENT_SERVICE_H
+
+#include "Reporter.h"
+
+#include <android/os/BnIncidentManager.h>
+#include <utils/Looper.h>
+
+#include <deque>
+#include <mutex>
+
+using namespace android;
+using namespace android::base;
+using namespace android::binder;
+using namespace android::os;
+using namespace std;
+
+// ================================================================================
+class ReportRequestQueue : public virtual RefBase
+{
+public:
+    ReportRequestQueue();
+    virtual ~ReportRequestQueue();
+
+    void addRequest(const sp<ReportRequest>& request);
+    sp<ReportRequest> getNextRequest();
+
+private:
+    mutex mLock;
+    deque<sp<ReportRequest> > mQueue;
+};
+
+
+// ================================================================================
+class ReportHandler : public MessageHandler
+{
+public:
+    ReportHandler(const sp<Looper>& handlerLooper, const sp<ReportRequestQueue>& queue);
+    virtual ~ReportHandler();
+
+    virtual void handleMessage(const Message& message);
+
+    /**
+     * Adds a ReportRequest to the queue.
+     */
+    void scheduleRunReport(const sp<ReportRequest>& request);
+
+    /**
+     * Resets mBacklogDelay to the default and schedules sending
+     * the messages to dropbox.
+     */
+    void scheduleSendBacklogToDropbox();
+
+private:
+    mutex mLock;
+    nsecs_t mBacklogDelay;
+    sp<Looper> mHandlerLooper;
+    sp<ReportRequestQueue> mQueue;
+
+    /**
+     * Runs all of the reports that have been queued.
+     */
+    void run_report();
+
+    /**
+     * Schedules a dropbox task mBacklogDelay nanoseconds from now.
+     */
+    void schedule_send_backlog_to_dropbox_locked();
+
+    /**
+     * Sends the backlog to the dropbox service.
+     */
+    void send_backlog_to_dropbox();
+};
+
+
+// ================================================================================
+class IncidentService : public BnIncidentManager {
+public:
+    IncidentService(const sp<Looper>& handlerLooper);
+    virtual ~IncidentService();
+
+    virtual Status reportIncident(const IncidentReportArgs& args);
+
+    virtual Status reportIncidentToStream(const IncidentReportArgs& args,
+            const sp<IIncidentReportStatusListener>& listener, const unique_fd& stream);
+
+    virtual Status systemRunning();
+
+private:
+    sp<ReportRequestQueue> mQueue;
+    sp<ReportHandler> mHandler;
+};
+
+
+#endif // INCIDENT_SERVICE_H
diff --git a/cmds/incidentd/src/Reporter.cpp b/cmds/incidentd/src/Reporter.cpp
new file mode 100644
index 0000000..1ecb291
--- /dev/null
+++ b/cmds/incidentd/src/Reporter.cpp
@@ -0,0 +1,352 @@
+/*
+ * 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_TAG "incidentd"
+
+#include "Reporter.h"
+#include "protobuf.h"
+
+#include "report_directory.h"
+#include "section_list.h"
+
+#include <private/android_filesystem_config.h>
+#include <android/os/DropBoxManager.h>
+#include <utils/SystemClock.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <errno.h>
+
+/**
+ * The directory where the incident reports are stored.
+ */
+static const String8 INCIDENT_DIRECTORY("/data/incidents");
+
+static status_t
+write_all(int fd, uint8_t const* buf, size_t size)
+{
+    while (size > 0) {
+        ssize_t amt = ::write(fd, buf, size);
+        if (amt < 0) {
+            return -errno;
+        }
+        size -= amt;
+        buf += amt;
+    }
+    return NO_ERROR;
+}
+
+// ================================================================================
+ReportRequest::ReportRequest(const IncidentReportArgs& a,
+            const sp<IIncidentReportStatusListener> &l, int f)
+    :args(a),
+     listener(l),
+     fd(f),
+     err(NO_ERROR)
+{
+}
+
+ReportRequest::~ReportRequest()
+{
+}
+
+// ================================================================================
+ReportRequestSet::ReportRequestSet()
+    :mRequests(),
+     mWritableCount(0),
+     mMainFd(-1)
+{
+}
+
+ReportRequestSet::~ReportRequestSet()
+{
+}
+
+void
+ReportRequestSet::add(const sp<ReportRequest>& request)
+{
+    mRequests.push_back(request);
+    mWritableCount++;
+}
+
+void
+ReportRequestSet::setMainFd(int fd)
+{
+    mMainFd = fd;
+    mWritableCount++;
+}
+
+status_t
+ReportRequestSet::write(uint8_t const* buf, size_t size)
+{
+    status_t err = EBADF;
+
+    // The streaming ones
+    int const N = mRequests.size();
+    for (int i=N-1; i>=0; i--) {
+        sp<ReportRequest> request = mRequests[i];
+        if (request->fd >= 0 && request->err == NO_ERROR) {
+            err = write_all(request->fd, buf, size);
+            if (err != NO_ERROR) {
+                request->err = err;
+                mWritableCount--;
+            }
+        }
+    }
+
+    // The dropbox file
+    if (mMainFd >= 0) {
+        err = write_all(mMainFd, buf, size);
+        if (err != NO_ERROR) {
+            mMainFd = -1;
+            mWritableCount--;
+        }
+    }
+
+    // Return an error only when there are no FDs to write.
+    return mWritableCount > 0 ? NO_ERROR : err;
+}
+
+
+// ================================================================================
+Reporter::Reporter()
+    :args(),
+     batch()
+{
+    char buf[100];
+
+    // TODO: Make the max size smaller for user builds.
+    mMaxSize = 100 * 1024 * 1024;
+    mMaxCount = 100;
+
+    // There can't be two at the same time because it's on one thread.
+    mStartTime = time(NULL);
+    strftime(buf, sizeof(buf), "/incident-%Y%m%d-%H%M%S", localtime(&mStartTime));
+    mFilename = INCIDENT_DIRECTORY + buf;
+}
+
+Reporter::~Reporter()
+{
+}
+
+Reporter::run_report_status_t
+Reporter::runReport()
+{
+
+    status_t err = NO_ERROR;
+    bool needMainFd = false;
+    int mainFd = -1;
+
+    // See if we need the main file
+    for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
+        if ((*it)->fd < 0 && mainFd < 0) {
+            needMainFd = true;
+            break;
+        }
+    }
+    if (needMainFd) {
+        // Create the directory
+        err = create_directory(INCIDENT_DIRECTORY);
+        if (err != NO_ERROR) {
+            goto done;
+        }
+
+        // If there are too many files in the directory (for whatever reason),
+        // delete the oldest ones until it's under the limit. Doing this first
+        // does mean that we can go over, so the max size is not a hard limit.
+        clean_directory(INCIDENT_DIRECTORY, mMaxSize, mMaxCount);
+
+        // Open the file.
+        err = create_file(&mainFd);
+        if (err != NO_ERROR) {
+            goto done;
+        }
+
+        // Add to the set
+        batch.setMainFd(mainFd);
+    }
+
+    // Tell everyone that we're starting.
+    for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
+        if ((*it)->listener != NULL) {
+            (*it)->listener->onReportStarted();
+        }
+    }
+
+    // Write the incident headers
+    for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
+        const sp<ReportRequest> request = (*it);
+        const vector<vector<int8_t>>& headers = request->args.headers();
+
+        for (vector<vector<int8_t>>::const_iterator buf=headers.begin(); buf!=headers.end();
+                buf++) {
+            int fd = request->fd >= 0 ? request->fd : mainFd;
+
+            uint8_t buffer[20];
+            uint8_t* p = write_length_delimited_tag_header(buffer, FIELD_ID_INCIDENT_HEADER,
+                    buf->size());
+            write_all(fd, buffer, p-buffer);
+
+            write_all(fd, (uint8_t const*)buf->data(), buf->size());
+            // If there was an error now, there will be an error later and we will remove
+            // it from the list then.
+        }
+    }
+
+    // For each of the report fields, see if we need it, and if so, execute the command
+    // and report to those that care that we're doing it.
+    for (const Section** section=SECTION_LIST; *section; section++) {
+        const int id = (*section)->id;
+        ALOGD("Taking incident report section %d '%s'", id, (*section)->name.string());
+
+        if (this->args.containsSection(id)) {
+            // Notify listener of starting
+            for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
+                if ((*it)->listener != NULL && (*it)->args.containsSection(id)) {
+                    (*it)->listener->onReportSectionStatus(id,
+                            IIncidentReportStatusListener::STATUS_STARTING);
+                }
+            }
+
+            // Execute - go get the data and write it into the file descriptors.
+            err = (*section)->Execute(&batch);
+            if (err != NO_ERROR) {
+                ALOGW("Incident section %s (%d) failed. Stopping report.",
+                        (*section)->name.string(), id);
+                goto done;
+            }
+
+            // Notify listener of starting
+            for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
+                if ((*it)->listener != NULL && (*it)->args.containsSection(id)) {
+                    (*it)->listener->onReportSectionStatus(id,
+                            IIncidentReportStatusListener::STATUS_FINISHED);
+                }
+            }
+        }
+    }
+
+done:
+    // Close the file.
+    if (mainFd >= 0) {
+        close(mainFd);
+    }
+
+    // Tell everyone that we're done.
+    for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
+        if ((*it)->listener != NULL) {
+            if (err == NO_ERROR) {
+                (*it)->listener->onReportFinished();
+            } else {
+                (*it)->listener->onReportFailed();
+            }
+        }
+    }
+
+    // Put the report into dropbox.
+    if (needMainFd && err == NO_ERROR) {
+        sp<DropBoxManager> dropbox = new DropBoxManager();
+        Status status = dropbox->addFile(String16("incident"), mFilename, 0);
+        ALOGD("Incident report done. dropbox status=%s\n", status.toString8().string());
+        if (!status.isOk()) {
+            return REPORT_NEEDS_DROPBOX;
+        }
+
+        // If the status was ok, delete the file. If not, leave it around until the next
+        // boot or the next checkin. If the directory gets too big older files will
+        // be rotated out.
+        unlink(mFilename.c_str());
+    }
+
+    return REPORT_FINISHED;
+}
+
+/**
+ * Create our output file and set the access permissions to -rw-rw----
+ */
+status_t
+Reporter::create_file(int* fd)
+{
+    const char* filename = mFilename.c_str();
+
+    *fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, 0660);
+    if (*fd < 0) {
+        ALOGE("Couldn't open incident file: %s (%s)", filename, strerror(errno));
+        return -errno;
+    }
+
+    // Override umask. Not super critical. If it fails go on with life.
+    chmod(filename, 0660);
+
+    if (chown(filename, AID_SYSTEM, AID_SYSTEM)) {
+        ALOGE("Unable to change ownership of incident file %s: %s\n", filename, strerror(errno));
+        status_t err = -errno;
+        unlink(mFilename.c_str());
+        return err;
+    }
+
+    return NO_ERROR;
+}
+
+// ================================================================================
+Reporter::run_report_status_t
+Reporter::upload_backlog()
+{
+    DIR* dir;
+    struct dirent* entry;
+    struct stat st;
+
+    if ((dir = opendir(INCIDENT_DIRECTORY.string())) == NULL) {
+        ALOGE("Couldn't open incident directory: %s", INCIDENT_DIRECTORY.string());
+        return REPORT_NEEDS_DROPBOX;
+    }
+
+    String8 dirbase(INCIDENT_DIRECTORY + "/");
+    sp<DropBoxManager> dropbox = new DropBoxManager();
+
+    // Enumerate, count and add up size
+    while ((entry = readdir(dir)) != NULL) {
+        if (entry->d_name[0] == '.') {
+            continue;
+        }
+        String8 filename = dirbase + entry->d_name;
+        if (stat(filename.string(), &st) != 0) {
+            ALOGE("Unable to stat file %s", filename.string());
+            continue;
+        }
+        if (!S_ISREG(st.st_mode)) {
+            continue;
+        }
+
+        Status status = dropbox->addFile(String16("incident"), filename.string(), 0);
+        ALOGD("Incident report done. dropbox status=%s\n", status.toString8().string());
+        if (!status.isOk()) {
+            return REPORT_NEEDS_DROPBOX;
+        }
+
+        // If the status was ok, delete the file. If not, leave it around until the next
+        // boot or the next checkin. If the directory gets too big older files will
+        // be rotated out.
+        unlink(filename.string());
+    }
+
+    closedir(dir);
+
+    return REPORT_FINISHED;
+}
+
diff --git a/cmds/incidentd/src/Reporter.h b/cmds/incidentd/src/Reporter.h
new file mode 100644
index 0000000..5b86561
--- /dev/null
+++ b/cmds/incidentd/src/Reporter.h
@@ -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.
+ */
+
+#ifndef REPORTER_H
+#define REPORTER_H
+
+#include <android/os/IIncidentReportStatusListener.h>
+#include <android/os/IncidentReportArgs.h>
+
+#include <string>
+#include <vector>
+
+#include <time.h>
+
+using namespace android;
+using namespace android::os;
+using namespace std;
+
+// ================================================================================
+struct ReportRequest : public virtual RefBase
+{
+    IncidentReportArgs args;
+    sp<IIncidentReportStatusListener> listener;
+    int fd;
+    status_t err;
+
+    ReportRequest(const IncidentReportArgs& args,
+            const sp<IIncidentReportStatusListener> &listener, int fd);
+    virtual ~ReportRequest();
+};
+
+// ================================================================================
+class ReportRequestSet
+{
+public:
+    ReportRequestSet();
+    ~ReportRequestSet();
+
+    void add(const sp<ReportRequest>& request);
+    void setMainFd(int fd);
+
+    // Write to all of the fds for the requests. If a write fails, it stops
+    // writing to that fd and returns NO_ERROR. When we are out of fds to write
+    // to it returns an error.
+    status_t write(uint8_t const* buf, size_t size);
+
+    typedef vector<sp<ReportRequest>>::iterator iterator;
+
+    iterator begin() { return mRequests.begin(); }
+    iterator end() { return mRequests.end(); }
+
+private:
+    vector<sp<ReportRequest>> mRequests;
+    int mWritableCount;
+    int mMainFd;
+};
+
+// ================================================================================
+class Reporter : public virtual RefBase
+{
+public:
+    enum run_report_status_t {
+        REPORT_FINISHED = 0,
+        REPORT_NEEDS_DROPBOX = 1
+    };
+
+    IncidentReportArgs args;
+    ReportRequestSet batch;
+
+    Reporter();
+    virtual ~Reporter();
+
+    // Run the report as described in the batch and args parameters.
+    run_report_status_t runReport();
+
+    static run_report_status_t upload_backlog();
+
+private:
+    string mFilename;
+    off_t mMaxSize;
+    size_t mMaxCount;
+    time_t mStartTime;
+
+    status_t create_file(int* fd);
+};
+
+
+#endif // REPORTER_H
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
new file mode 100644
index 0000000..fac299e
--- /dev/null
+++ b/cmds/incidentd/src/Section.cpp
@@ -0,0 +1,292 @@
+/*
+ * 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_TAG "incidentd"
+
+#include "Section.h"
+#include "protobuf.h"
+
+#include <binder/IServiceManager.h>
+#include <mutex>
+
+using namespace std;
+
+const int64_t REMOTE_CALL_TIMEOUT_MS = 10 * 1000; // 10 seconds
+
+// ================================================================================
+Section::Section(int i)
+    :id(i)
+{
+}
+
+Section::~Section()
+{
+}
+
+status_t
+Section::WriteHeader(ReportRequestSet* requests, size_t size) const
+{
+    ssize_t amt;
+    uint8_t buf[20];
+    uint8_t* p = write_length_delimited_tag_header(buf, this->id, size);
+    return requests->write(buf, p-buf);
+}
+
+// ================================================================================
+struct WorkerThreadData : public virtual RefBase
+{
+    const WorkerThreadSection* section;
+    int fds[2];
+
+    // Lock protects these fields
+    mutex lock;
+    bool workerDone;
+    status_t workerError;
+
+    WorkerThreadData(const WorkerThreadSection* section);
+    virtual ~WorkerThreadData();
+
+    int readFd() { return fds[0]; }
+    int writeFd() { return fds[1]; }
+};
+
+WorkerThreadData::WorkerThreadData(const WorkerThreadSection* sec)
+    :section(sec),
+     workerDone(false),
+     workerError(NO_ERROR)
+{
+    fds[0] = -1;
+    fds[1] = -1;
+}
+
+WorkerThreadData::~WorkerThreadData()
+{
+}
+
+// ================================================================================
+WorkerThreadSection::WorkerThreadSection(int id)
+    :Section(id)
+{
+}
+
+WorkerThreadSection::~WorkerThreadSection()
+{
+}
+
+static void*
+worker_thread_func(void* cookie)
+{
+    WorkerThreadData* data = (WorkerThreadData*)cookie;
+    status_t err = data->section->BlockingCall(data->writeFd());
+
+    {
+        unique_lock<mutex> lock(data->lock);
+        data->workerDone = true;
+        data->workerError = err;
+    }
+
+    close(data->writeFd());
+    data->decStrong(data->section);
+    // data might be gone now. don't use it after this point in this thread.
+    return NULL;
+}
+
+status_t
+WorkerThreadSection::Execute(ReportRequestSet* requests) const
+{
+    status_t err = NO_ERROR;
+    pthread_t thread;
+    pthread_attr_t attr;
+    bool timedOut = false;
+    FdBuffer buffer;
+
+    // Data shared between this thread and the worker thread.
+    sp<WorkerThreadData> data = new WorkerThreadData(this);
+
+    // Create the pipe
+    err = pipe(data->fds);
+    if (err != 0) {
+        return -errno;
+    }
+
+    // The worker thread needs a reference and we can't let the count go to zero
+    // if that thread is slow to start.
+    data->incStrong(this);
+
+    // Create the thread
+    err = pthread_attr_init(&attr);
+    if (err != 0) {
+        return -err;
+    }
+    // TODO: Do we need to tweak thread priority?
+    err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+    if (err != 0) {
+        pthread_attr_destroy(&attr);
+        return -err;
+    }
+    err = pthread_create(&thread, &attr, worker_thread_func, (void*)data.get());
+    if (err != 0) {
+        pthread_attr_destroy(&attr);
+        return -err;
+    }
+    pthread_attr_destroy(&attr);
+
+    // Loop reading until either the timeout or the worker side is done (i.e. eof).
+    err = buffer.read(data->readFd(), REMOTE_CALL_TIMEOUT_MS);
+    if (err != NO_ERROR) {
+        // TODO: Log this error into the incident report.
+        ALOGW("WorkerThreadSection '%s' reader failed with error '%s'", this->name.string(),
+                strerror(-err));
+    }
+
+    // Done with the read fd. The worker thread closes the write one so
+    // we never race and get here first.
+    close(data->readFd());
+
+    // If the worker side is finished, then return its error (which may overwrite
+    // our possible error -- but it's more interesting anyway).  If not, then we timed out.
+    {
+        unique_lock<mutex> lock(data->lock);
+        if (!data->workerDone) {
+            // We timed out
+            timedOut = true;
+        } else {
+            if (data->workerError != NO_ERROR) {
+                err = data->workerError;
+                // TODO: Log this error into the incident report.
+                ALOGW("WorkerThreadSection '%s' worker failed with error '%s'", this->name.string(),
+                        strerror(-err));
+            }
+        }
+    }
+
+    if (timedOut || buffer.timedOut()) {
+        ALOGW("WorkerThreadSection '%s' timed out", this->name.string());
+        return NO_ERROR;
+    }
+
+    if (buffer.truncated()) {
+        // TODO: Log this into the incident report.
+    }
+
+    // TODO: There was an error with the command or buffering. Report that.  For now
+    // just exit with a log messasge.
+    if (err != NO_ERROR) {
+        ALOGW("WorkerThreadSection '%s' failed with error '%s'", this->name.string(),
+                strerror(-err));
+        return NO_ERROR;
+    }
+
+    // Write the data that was collected
+    ALOGD("section '%s' wrote %zd bytes in %d ms", name.string(), buffer.size(),
+            (int)buffer.durationMs());
+    WriteHeader(requests, buffer.size());
+    err = buffer.write(requests);
+    if (err != NO_ERROR) {
+        ALOGW("WorkerThreadSection '%s' failed writing: '%s'", this->name.string(), strerror(-err));
+        return err;
+    }
+
+    return NO_ERROR;
+}
+
+// ================================================================================
+CommandSection::CommandSection(int id, const char* first, ...)
+    :Section(id)
+{
+    va_list args;
+    int count = 0;
+
+    va_start(args, first);
+    while (va_arg(args, const char*) != NULL) {
+        count++;
+    }
+    va_end(args);
+
+    mCommand = (const char**)malloc(sizeof(const char*) * count);
+
+    mCommand[0] = first;
+    name = first;
+    name += " ";
+    va_start(args, first);
+    for (int i=0; i<count; i++) {
+        const char* arg = va_arg(args, const char*); 
+        mCommand[i+1] = arg;
+        if (arg != NULL) {
+            name += va_arg(args, const char*);
+            name += " ";
+        }
+    }
+    va_end(args);
+}
+
+CommandSection::~CommandSection()
+{
+}
+
+status_t
+CommandSection::Execute(ReportRequestSet* /*requests*/) const
+{
+    return NO_ERROR;
+}
+
+// ================================================================================
+DumpsysSection::DumpsysSection(int id, const char* service, ...)
+    :WorkerThreadSection(id),
+     mService(service)
+{
+    name = "dumpsys ";
+    name += service;
+
+    va_list args;
+    va_start(args, service);
+    while (true) {
+        const char* arg = va_arg(args, const char*); 
+        if (arg == NULL) {
+            break;
+        }
+        mArgs.add(String16(arg));
+        name += " ";
+        name += arg;
+    }
+    va_end(args);
+}
+
+DumpsysSection::~DumpsysSection()
+{
+}
+
+status_t
+DumpsysSection::BlockingCall(int pipeWriteFd) const
+{
+    // checkService won't wait for the service to show up like getService will.
+    sp<IBinder> service = defaultServiceManager()->checkService(mService);
+    
+    if (service == NULL) {
+        // Returning an error interrupts the entire incident report, so just
+        // log the failure.
+        // TODO: have a meta record inside the report that would log this
+        // failure inside the report, because the fact that we can't find
+        // the service is good data in and of itself. This is running in
+        // another thread so lock that carefully...
+        ALOGW("DumpsysSection: Can't lookup service: %s", String8(mService).string());
+        return NO_ERROR;
+    }
+
+    service->dump(pipeWriteFd, mArgs);
+
+    return NO_ERROR;
+}
diff --git a/cmds/incidentd/src/Section.h b/cmds/incidentd/src/Section.h
new file mode 100644
index 0000000..35740e9
--- /dev/null
+++ b/cmds/incidentd/src/Section.h
@@ -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.
+ */
+
+#ifndef SECTIONS_H
+#define SECTIONS_H
+
+#include "FdBuffer.h"
+
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+using namespace android;
+
+/**
+ * Base class for sections
+ */
+class Section
+{
+public:
+    int id;
+    String8 name;
+
+    Section(int id);
+    virtual ~Section();
+
+    virtual status_t Execute(ReportRequestSet* requests) const = 0;
+
+    status_t WriteHeader(ReportRequestSet* requests, size_t size) const;
+};
+
+/**
+ * Section that reads in a file.
+ */
+class FileSection : public Section
+{
+public:
+    FileSection(int id, const char* filename);
+    virtual ~FileSection();
+
+    virtual status_t Execute(ReportRequestSet* requests) const;
+
+private:
+    const char* mFilename;
+};
+
+/**
+ * Base class for sections that call a command that might need a timeout.
+ */
+class WorkerThreadSection : public Section
+{
+public:
+    WorkerThreadSection(int id);
+    virtual ~WorkerThreadSection();
+
+    virtual status_t Execute(ReportRequestSet* requests) const;
+
+    virtual status_t BlockingCall(int pipeWriteFd) const = 0;
+};
+
+/**
+ * Section that forks and execs a command, and puts stdout as the section.
+ */
+class CommandSection : public Section
+{
+public:
+    CommandSection(int id, const char* first, ...);
+    virtual ~CommandSection();
+
+    virtual status_t Execute(ReportRequestSet* requests) const;
+
+private:
+    const char** mCommand;
+};
+
+/**
+ * Section that calls dumpsys on a system service.
+ */
+class DumpsysSection : public WorkerThreadSection
+{
+public:
+    DumpsysSection(int id, const char* service, ...);
+    virtual ~DumpsysSection();
+
+    virtual status_t BlockingCall(int pipeWriteFd) const;
+
+private:
+    String16 mService;
+    Vector<String16> mArgs;
+};
+
+#endif // SECTIONS_H
+
diff --git a/cmds/incidentd/src/main.cpp b/cmds/incidentd/src/main.cpp
new file mode 100644
index 0000000..3a7511d
--- /dev/null
+++ b/cmds/incidentd/src/main.cpp
@@ -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.
+ */
+
+#define LOG_TAG "incidentd"
+
+#include "IncidentService.h"
+
+#include <binder/IInterface.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <binder/Status.h>
+#include <cutils/log.h>
+#include <utils/Looper.h>
+#include <utils/StrongPointer.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+using namespace android;
+
+// ================================================================================
+int
+main(int /*argc*/, char** /*argv*/)
+{
+    // Set up the looper
+    sp<Looper> looper(Looper::prepare(0 /* opts */));
+
+    // Set up the binder
+    sp<ProcessState> ps(ProcessState::self());
+    ps->setThreadPoolMaxThreadCount(1); // everything is oneway, let it queue and save ram
+    ps->startThreadPool();
+    ps->giveThreadPoolName();
+    IPCThreadState::self()->disableBackgroundScheduling(true);
+
+    // Create the service
+    android::sp<IncidentService> service = new IncidentService(looper);
+    if (defaultServiceManager()->addService(String16("incident"), service) != 0) {
+        ALOGE("Failed to add service");
+        return -1;
+    }
+
+    // Loop forever -- the reports run on this thread in a handler, and the
+    // binder calls remain responsive in their pool of one thread.
+    while (true) {
+        looper->pollAll(-1 /* timeoutMillis */);
+    }
+    ALOGW("incidentd escaped from its loop.");
+
+    return 1;
+}
diff --git a/cmds/incidentd/src/protobuf.cpp b/cmds/incidentd/src/protobuf.cpp
new file mode 100644
index 0000000..cb864fd
--- /dev/null
+++ b/cmds/incidentd/src/protobuf.cpp
@@ -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.
+ */
+
+#include "protobuf.h"
+
+uint8_t*
+write_raw_varint(uint8_t* buf, uint32_t val)
+{
+    uint8_t* p = buf;
+    while (true) {
+        if ((val & ~0x7F) == 0) {
+            *p++ = (uint8_t)val;
+            return p;
+        } else {
+            *p++ = (uint8_t)((val & 0x7F) | 0x80);
+            val >>= 7;
+        }
+    }
+}
+
+uint8_t*
+write_length_delimited_tag_header(uint8_t* buf, uint32_t fieldId, size_t size)
+{
+    buf = write_raw_varint(buf, (fieldId << 3) | 2);
+    buf = write_raw_varint(buf, size);
+    return buf;
+}
+
diff --git a/cmds/incidentd/src/protobuf.h b/cmds/incidentd/src/protobuf.h
new file mode 100644
index 0000000..a243998
--- /dev/null
+++ b/cmds/incidentd/src/protobuf.h
@@ -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.
+ */
+
+#ifndef PROTOBUF_H
+#define PROTOBUF_H
+
+#include <stdint.h>
+
+/**
+ * Write a varint into the buffer. Return the next position to write at.
+ * There must be 10 bytes in the buffer. The same as EncodedBuffer.writeRawVarint32
+ */
+uint8_t* write_raw_varint(uint8_t* buf, uint32_t val);
+
+/**
+ * Write a protobuf WIRE_TYPE_LENGTH_DELIMITED header. Return the next position to write at.
+ * There must be 20 bytes in the buffer.
+ */
+uint8_t* write_length_delimited_tag_header(uint8_t* buf, uint32_t fieldId, size_t size);
+
+enum {
+    // IncidentProto.header
+    FIELD_ID_INCIDENT_HEADER = 1
+};
+
+#endif // PROTOBUF_H
+
diff --git a/cmds/incidentd/src/report_directory.cpp b/cmds/incidentd/src/report_directory.cpp
new file mode 100644
index 0000000..f60b8ac
--- /dev/null
+++ b/cmds/incidentd/src/report_directory.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.
+ */
+
+#define LOG_TAG "incidentd"
+
+#include "report_directory.h"
+
+#include <cutils/log.h>
+#include <private/android_filesystem_config.h>
+#include <utils/String8.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <libgen.h>
+#include <unistd.h>
+
+#include <vector>
+
+using namespace android;
+using namespace std;
+
+status_t
+create_directory(const char* directory)
+{
+    struct stat st;
+    status_t err = NO_ERROR;
+    char* dir = strdup(directory);
+
+    // Skip first slash
+    char* d = dir + 1;
+
+    // Create directories, assigning them to the system user
+    bool last = false;
+    while (!last) {
+        d = strchr(d, '/');
+        if (d != NULL) {
+            *d = '\0';
+        } else {
+            last = true;
+        }
+        if (stat(dir, &st) == 0) {
+            if (!S_ISDIR(st.st_mode)) {
+                err = ALREADY_EXISTS;
+                goto done;
+            }
+        } else {
+            if (mkdir(dir, 0770)) {
+                ALOGE("No incident reports today. "
+                        "Unable to create incident report dir %s: %s", dir,
+                        strerror(errno));
+                err = -errno;
+                goto done;
+            }
+            if (chmod(dir, 0770)) {
+                ALOGE("No incident reports today. "
+                        "Unable to set permissions for incident report dir %s: %s", dir,
+                        strerror(errno));
+                err = -errno;
+                goto done;
+            }
+            if (chown(dir, AID_SYSTEM, AID_SYSTEM)) {
+                ALOGE("No incident reports today. Unable to change ownership of dir %s: %s\n",
+                        dir, strerror(errno));
+                err = -errno;
+                goto done;
+            }
+        }
+        if (!last) {
+            *d++ = '/';
+        }
+    }
+
+    // Ensure that the final directory is owned by the system with 0770. If it isn't
+    // we won't write into it.
+    if (stat(directory, &st) != 0) {
+        ALOGE("No incident reports today. Can't stat: %s", directory);
+        err = -errno;
+        goto done;
+    }
+    if ((st.st_mode & 0777) != 0770) {
+        ALOGE("No incident reports today. Mode is %0o on report directory %s",
+                st.st_mode, directory);
+        err = BAD_VALUE;
+        goto done;
+    }
+    if (st.st_uid != AID_SYSTEM || st.st_gid != AID_SYSTEM) {
+        ALOGE("No incident reports today. Owner is %d and group is %d on report directory %s",
+                st.st_uid, st.st_gid, directory);
+        err = BAD_VALUE;
+        goto done;
+    }
+
+done:
+    free(dir);
+    return err;
+}
+
+static bool
+stat_mtime_cmp(const pair<String8,struct stat>& a, const pair<String8,struct stat>& b)
+{
+    return a.second.st_mtime < b.second.st_mtime;
+}
+
+void
+clean_directory(const char* directory, off_t maxSize, size_t maxCount)
+{
+    DIR* dir;
+    struct dirent* entry;
+    struct stat st;
+
+    vector<pair<String8,struct stat>> files;
+
+    if ((dir = opendir(directory)) == NULL) {
+        ALOGE("Couldn't open incident directory: %s", directory);
+        return;
+    }
+
+    String8 dirbase(String8(directory) + "/");
+
+    off_t totalSize = 0;
+    size_t totalCount = 0;
+
+    // Enumerate, count and add up size
+    while ((entry = readdir(dir)) != NULL) {
+        if (entry->d_name[0] == '.') {
+            continue;
+        }
+        String8 filename = dirbase + entry->d_name;
+        if (stat(filename.string(), &st) != 0) {
+            ALOGE("Unable to stat file %s", filename.string());
+            continue;
+        }
+        if (!S_ISREG(st.st_mode)) {
+            continue;
+        }
+        files.push_back(pair<String8,struct stat>(filename, st));
+
+        totalSize += st.st_size;
+        totalCount++;
+    }
+
+    closedir(dir);
+
+    // Count or size is less than max, then we're done.
+    if (totalSize < maxSize && totalCount < maxCount) {
+        return;
+    }
+
+    // Oldest files first.
+    sort(files.begin(), files.end(), stat_mtime_cmp);
+
+    // Remove files until we're under our limits.
+    for (vector<pair<String8,struct stat>>::iterator it = files.begin();
+            it != files.end() && totalSize >= maxSize && totalCount >= maxCount; it++) {
+        remove(it->first.string());
+        totalSize -= it->second.st_size;
+        totalCount--;
+    }
+}
diff --git a/cmds/incidentd/src/report_directory.h b/cmds/incidentd/src/report_directory.h
new file mode 100644
index 0000000..bed4f86
--- /dev/null
+++ b/cmds/incidentd/src/report_directory.h
@@ -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.
+ */
+
+#ifndef DIRECTORY_CLEANER_H
+#define DIRECTORY_CLEANER_H
+
+#include <utils/Errors.h>
+
+#include <sys/types.h>
+
+using namespace android;
+
+status_t create_directory(const char* directory);
+void clean_directory(const char* directory, off_t maxSize, size_t maxCount);
+
+#endif // DIRECTORY_CLEANER_H
diff --git a/cmds/incidentd/src/section_list.cpp b/cmds/incidentd/src/section_list.cpp
new file mode 100644
index 0000000..b6112ed
--- /dev/null
+++ b/cmds/incidentd/src/section_list.cpp
@@ -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.
+ */
+
+#include "section_list.h"
+
+//using namespace android::util;
+
+/**
+ * This is the mapping of section IDs to the commands that are run to get those commands.
+ */
+const Section* SECTION_LIST[] = {
+    new DumpsysSection(3000,
+            "fingerprint", "--proto", "--incident", NULL),
+    NULL
+};
+
diff --git a/cmds/incidentd/src/section_list.h b/cmds/incidentd/src/section_list.h
new file mode 100644
index 0000000..c977519
--- /dev/null
+++ b/cmds/incidentd/src/section_list.h
@@ -0,0 +1,28 @@
+/*
+ * 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 SECTION_LIST_H
+#define SECTION_LIST_H
+
+#include "Section.h"
+
+/**
+ * This is the mapping of section IDs to the commands that are run to get those commands.
+ */
+extern const Section* SECTION_LIST[];
+
+#endif // SECTION_LIST_H
+
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 6dd488f..2ccfe0e 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -45,6 +45,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ParceledListSlice;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -75,6 +76,7 @@
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
 import android.text.TextAssistant;
+import android.text.TextClassificationManager;
 import android.text.TextUtils;
 import android.text.method.TextKeyListener;
 import android.transition.Scene;
@@ -1402,7 +1404,7 @@
         if (mTextAssistant != null) {
             return mTextAssistant;
         }
-        return TextAssistant.NO_OP;
+        return getSystemService(TextClassificationManager.class);
     }
 
     /**
@@ -1737,8 +1739,8 @@
                                 FillableInputField autoFillField = (FillableInputField) field;
                                 final int viewId = autoFillField.getId();
                                 final View view = root.findViewByAccessibilityIdTraversal(viewId);
-                                // TODO: should handle other types of view as well, but that will
-                                // require:
+                                // TODO(b/33197203): should handle other types of view as well, but
+                                // that will require:
                                 // - a new interface like AutoFillable
                                 // - a way for the views to define the type of the autofield value
                                 if ((view instanceof EditText)) {
@@ -1751,7 +1753,7 @@
                     @Override
                     public void showError(String message) {
                         runOnUiThread(() -> {
-                            // TODO: temporary show a toast until it uses the Snack bar.
+                            // TODO(b/33197203): temporary show a toast until it uses the Snack bar.
                             Toast.makeText(Activity.this, "Auto-fill request failed: " + message,
                                     Toast.LENGTH_LONG).show();
                         });
@@ -2018,7 +2020,29 @@
     }
 
     /**
-     * Updates the aspect ratio of the current picture-in-picture activity.
+     * Requests to the system that the activity can be automatically put into picture-in-picture
+     * mode when the user leaves the activity causing it normally to be hidden.  Generally, this
+     * happens when another task is brought to the forground or the task containing this activity
+     * is moved to the background.  This is a *not* a guarantee that the activity will actually be
+     * put in picture-in-picture mode, and depends on a number of factors, including whether there
+     * is already something in picture-in-picture.
+     *
+     * @param enterPictureInPictureOnMoveToBg whether or not this activity can automatically enter
+     *                                        picture-in-picture
+     */
+    public void enterPictureInPictureModeOnMoveToBackground(
+            boolean enterPictureInPictureOnMoveToBg) {
+        try {
+            ActivityManagerNative.getDefault().enterPictureInPictureModeOnMoveToBackground(mToken,
+                    enterPictureInPictureOnMoveToBg);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Updates the aspect ratio of the current picture-in-picture activity if this activity is
+     * already in picture-in-picture mode, or sets it to be used later if
+     * {@link #enterPictureInPictureModeOnMoveToBackground(boolean)} is requested.
      *
      * @param aspectRatio the new aspect ratio of the picture-in-picture.
      */
@@ -2030,23 +2054,19 @@
     }
 
     /**
-     * Requests to the system that the activity can be automatically put into picture-in-picture
-     * mode when the user leaves the activity causing it normally to be hidden.  This is a *not*
-     * a guarantee that the activity will actually be put in picture-in-picture mode, and depends
-     * on a number of factors, including whether there is already something in picture-in-picture.
+     * Updates the set of user actions associated with the picture-in-picture activity.
      *
-     * If {@param enterPictureInPictureOnMoveToBg} is true, then you may also call
-     * {@link #setPictureInPictureAspectRatio(float)} to specify the aspect ratio to automatically
-     * enter picture-in-picture with.
-     *
-     * @param enterPictureInPictureOnMoveToBg whether or not this activity can automatically enter
-     *                                     picture-in-picture
+     * @param actions the new actions for picture-in-picture (can be null to reset the set of
+     *                actions).  The maximum number of actions that will be displayed on this device
+     *                is defined by {@link ActivityManager#getMaxNumPictureInPictureActions()}.
      */
-    public void enterPictureInPictureModeOnMoveToBackground(
-            boolean enterPictureInPictureOnMoveToBg) {
+    public void setPictureInPictureActions(List<RemoteAction> actions) {
         try {
-            ActivityManagerNative.getDefault().enterPictureInPictureModeOnMoveToBackground(mToken,
-                    enterPictureInPictureOnMoveToBg);
+            if (actions == null) {
+                actions = new ArrayList<>();
+            }
+            ActivityManagerNative.getDefault().setPictureInPictureActions(mToken,
+                    new ParceledListSlice<RemoteAction>(actions));
         } catch (RemoteException e) {
         }
     }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 312d3a5..761da35 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -87,8 +87,9 @@
 
     private static int gMaxRecentTasks = -1;
 
+    private static final int NUM_ALLOWED_PIP_ACTIONS = 3;
+
     private final Context mContext;
-    private final Handler mHandler;
 
     private static volatile boolean sSystemReady = false;
 
@@ -450,9 +451,6 @@
     /** @hide requestType for assist context: generate full AssistStructure. */
     public static final int ASSIST_CONTEXT_FULL = 1;
 
-    /** @hide requestType for assist context: generate full AssistStructure for auto-fill. */
-    public static final int ASSIST_CONTEXT_AUTOFILL = 2;
-
     /** @hide Flag for registerUidObserver: report changes in process state. */
     public static final int UID_OBSERVER_PROCSTATE = 1<<0;
 
@@ -494,7 +492,6 @@
 
     /*package*/ ActivityManager(Context context, Handler handler) {
         mContext = context;
-        mHandler = handler;
     }
 
     /**
@@ -1005,6 +1002,24 @@
     }
 
     /**
+     * Returns true if the system supports split screen multi-window.
+     * @hide
+     */
+    static public boolean supportsSplitScreenMultiWindow() {
+        return supportsMultiWindow()
+                && Resources.getSystem().getBoolean(
+                    com.android.internal.R.bool.config_supportsSplitScreenMultiWindow);
+    }
+
+    /**
+     * Return the maximum number of actions that will be displayed in the picture-in-picture UI when
+     * the user interacts with the activity currently in picture-in-picture mode.
+     */
+    public static int getMaxNumPictureInPictureActions() {
+        return NUM_ALLOWED_PIP_ACTIONS;
+    }
+
+    /**
      * Information you can set and retrieve about the current activity within the recent task list.
      */
     public static class TaskDescription implements Parcelable {
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 913edfd8..87700dc 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -28,6 +28,8 @@
 
 import com.android.internal.app.IVoiceInteractor;
 
+import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -62,6 +64,36 @@
     public static final int APP_TRANSITION_TIMEOUT = 3;
 
     /**
+     * Class to hold deferred properties to apply for picture-in-picture for a given activity.
+     */
+    public static class PictureInPictureArguments {
+        /**
+         * The expected aspect ratio of the picture-in-picture.
+         */
+        public float aspectRatio;
+
+        /**
+         * The set of actions that are associated with this activity when in picture in picture.
+         */
+        public List<RemoteAction> userActions = new ArrayList<>();
+
+        public void dump(PrintWriter pw, String prefix) {
+            pw.println(prefix + "aspectRatio=" + aspectRatio);
+            if (userActions.isEmpty()) {
+                pw.println(prefix + "  userActions=[]");
+            } else {
+                pw.println(prefix + "  userActions=[");
+                for (int i = 0; i < userActions.size(); i++) {
+                    RemoteAction action = userActions.get(i);
+                    pw.print(prefix + "    Action[" + i + "]: ");
+                    action.dump("", pw);
+                }
+                pw.println(prefix + "  ]");
+            }
+        }
+    }
+
+    /**
      * Grant Uri permissions from one app to another. This method only extends
      * permission grants if {@code callingUid} has permission to them.
      */
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index f052bf7..e34fabc 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -88,6 +88,7 @@
 import android.provider.Settings;
 import android.security.NetworkSecurityPolicy;
 import android.security.net.config.NetworkSecurityConfigProvider;
+import android.service.autofill.AutoFillService;
 import android.service.autofill.IAutoFillCallback;
 import android.service.voice.VoiceInteractionSession;
 import android.util.AndroidRuntimeException;
@@ -112,9 +113,6 @@
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.renderscript.RenderScriptCacheDir;
-import android.system.Os;
-import android.system.OsConstants;
-import android.system.ErrnoException;
 import android.webkit.WebView;
 
 import com.android.internal.annotations.GuardedBy;
@@ -137,11 +135,9 @@
 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;
-import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -640,6 +636,7 @@
         IBinder requestToken;
         int requestType;
         int sessionId;
+        int flags;
     }
 
     static final class ActivityConfigChangeData {
@@ -651,8 +648,6 @@
         }
     }
 
-    private native void dumpGraphicsInfo(FileDescriptor fd);
-
     private class ApplicationThread extends IApplicationThread.Stub {
         private static final String DB_INFO_FORMAT = "  %8s %8s %14s %14s  %s";
 
@@ -1193,7 +1188,7 @@
 
         @Override
         public void dumpGfxInfo(ParcelFileDescriptor pfd, String[] args) {
-            dumpGraphicsInfo(pfd.getFileDescriptor());
+            nDumpGraphicsInfo(pfd.getFileDescriptor());
             WindowManagerGlobal.getInstance().dumpGfxInfo(pfd.getFileDescriptor(), args);
             IoUtils.closeQuietly(pfd);
         }
@@ -1245,12 +1240,13 @@
 
         @Override
         public void requestAssistContextExtras(IBinder activityToken, IBinder requestToken,
-                int requestType, int sessionId) {
+                int requestType, int sessionId, int flags) {
             RequestAssistContextExtras cmd = new RequestAssistContextExtras();
             cmd.activityToken = activityToken;
             cmd.requestToken = requestToken;
             cmd.requestType = requestType;
             cmd.sessionId = sessionId;
+            cmd.flags = flags;
             sendMessage(H.REQUEST_ASSIST_CONTEXT_EXTRAS, cmd);
         }
 
@@ -2883,6 +2879,16 @@
     }
 
     public void handleRequestAssistContextExtras(RequestAssistContextExtras cmd) {
+        // Filling for auto-fill has a few differences:
+        // - it does not need an AssistContent
+        // - it does not call onProvideAssistData()
+        // - it needs an IAutoFillCallback
+        // - it sets the flags so views can provide autofill-specific data (such as passwords)
+        boolean forAutoFill = (cmd.flags
+                & (View.ASSIST_FLAG_SANITIZED_TEXT
+                        | View.ASSIST_FLAG_NON_SANITIZED_TEXT)) != 0;
+
+        // TODO(b/33197203): decide if lastSessionId logic applies to auto-fill sessions
         if (mLastSessionId != cmd.sessionId) {
             // Clear the existing structures
             mLastSessionId = cmd.sessionId;
@@ -2894,46 +2900,45 @@
                 mLastAssistStructures.remove(i);
             }
         }
-        // Filling for auto-fill has a few differences:
-        // - it does not need an AssistContent
-        // - it does not call onProvideAssistData()
-        // - it needs an IAutoFillCallback
-        boolean forAutofill = cmd.requestType == ActivityManager.ASSIST_CONTEXT_AUTOFILL;
 
         Bundle data = new Bundle();
         AssistStructure structure = null;
-        AssistContent content = forAutofill ? null : new AssistContent();
+        AssistContent content = forAutoFill ? null : new AssistContent();
         ActivityClientRecord r = mActivities.get(cmd.activityToken);
         Uri referrer = null;
         if (r != null) {
-            r.activity.getApplication().dispatchOnProvideAssistData(r.activity, data);
-            if (!forAutofill) {
+            if (!forAutoFill) {
+                r.activity.getApplication().dispatchOnProvideAssistData(r.activity, data);
                 r.activity.onProvideAssistData(data);
             }
             referrer = r.activity.onProvideReferrer();
-            if (cmd.requestType == ActivityManager.ASSIST_CONTEXT_FULL || forAutofill) {
-                structure = new AssistStructure(r.activity);
+            if (cmd.requestType == ActivityManager.ASSIST_CONTEXT_FULL || forAutoFill) {
+                structure = new AssistStructure(r.activity, cmd.flags);
                 Intent activityIntent = r.activity.getIntent();
+                if (cmd.flags > 0) {
+                    data.putInt(VoiceInteractionSession.KEY_FLAGS, cmd.flags);
+                }
+                // TODO(b/33197203): re-evaluate conditions below for auto-fill. In particular,
+                // FLAG_SECURE might be allowed on AUTO_FILL but not on AUTO_FILL_SAVE)
                 if (activityIntent != null && (r.window == null ||
                         (r.window.getAttributes().flags
                                 & WindowManager.LayoutParams.FLAG_SECURE) == 0)) {
-                    Intent intent = new Intent(activityIntent);
-                    intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_WRITE_URI_PERMISSION
-                            | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION));
-                    intent.removeUnsafeExtras();
-                    if (forAutofill) {
+                    if (forAutoFill) {
                         IAutoFillCallback autoFillCallback = r.activity.getAutoFillCallback();
-                        data.putBinder(VoiceInteractionSession.KEY_AUTO_FILL_CALLBACK,
-                                autoFillCallback.asBinder());
+                        data.putBinder(AutoFillService.KEY_CALLBACK, autoFillCallback.asBinder());
                     } else {
+                        Intent intent = new Intent(activityIntent);
+                        intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+                                | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION));
+                        intent.removeUnsafeExtras();
                         content.setDefaultIntent(intent);
                     }
                 } else {
-                    if (!forAutofill) {
+                    if (!forAutoFill) {
                         content.setDefaultIntent(new Intent());
                     }
                 }
-                if (!forAutofill) {
+                if (!forAutoFill) {
                     r.activity.onProvideAssistContent(content);
                 }
             }
@@ -2941,6 +2946,7 @@
         if (structure == null) {
             structure = new AssistStructure();
         }
+        // TODO(b/33197203): decide if lastSessionId logic applies to auto-fill sessions
         mLastAssistStructures.add(new WeakReference<>(structure));
         IActivityManager mgr = ActivityManager.getService();
         try {
@@ -6227,4 +6233,8 @@
 
         throw new RuntimeException("Main thread loop unexpectedly exited");
     }
+
+    // ------------------ Regular JNI ------------------------
+
+    private native void nDumpGraphicsInfo(FileDescriptor fd);
 }
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index e378f4ad..fcc6e3d 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -474,6 +474,7 @@
     void enterPictureInPictureModeOnMoveToBackground(in IBinder token,
             boolean enterPictureInPictureOnMoveToBg);
     void setPictureInPictureAspectRatio(in IBinder token, float aspectRatio);
+    void setPictureInPictureActions(in IBinder token, in ParceledListSlice actions);
     void activityRelaunched(in IBinder token);
     IBinder getUriPermissionOwnerForActivity(in IBinder activityToken);
     /**
@@ -575,7 +576,7 @@
     void unregisterTaskStackListener(ITaskStackListener listener);
     void moveStackToDisplay(int stackId, int displayId);
     boolean requestAutoFillData(in IResultReceiver receiver, in Bundle receiverExtras,
-            in IBinder activityToken);
+            in IBinder activityToken, int flags);
     void dismissKeyguard(in IBinder token, in IKeyguardDismissCallback callback);
 
     // WARNING: when these transactions are updated, check if they are any callers on the native
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index 6b962b9..7f168c9 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -134,7 +134,7 @@
     void dumpDbInfo(in ParcelFileDescriptor fd, in String[] args);
     void unstableProviderDied(IBinder provider);
     void requestAssistContextExtras(IBinder activityToken, IBinder requestToken,
-            int requestType, int sessionId);
+            int requestType, int sessionId, int flags);
     void scheduleTranslucentConversionComplete(IBinder token, boolean timeout);
     void setProcessState(int state);
     void scheduleInstallProvider(in ProviderInfo provider);
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 927ef6c..2c4e7a0 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -99,8 +99,12 @@
     void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim);
     void setInterruptionFilter(String pkg, int interruptionFilter);
 
-    void applyAdjustmentFromAssistantService(in INotificationListener token, in Adjustment adjustment);
-    void applyAdjustmentsFromAssistantService(in INotificationListener token, in List<Adjustment> adjustments);
+    void applyAdjustmentFromAssistant(in INotificationListener token, in Adjustment adjustment);
+    void applyAdjustmentsFromAssistant(in INotificationListener token, in List<Adjustment> adjustments);
+    void createNotificationChannelFromAssistant(in INotificationListener token, String pkg, in NotificationChannel channel);
+    void updateNotificationChannelFromAssistant(in INotificationListener token, String pkg, in NotificationChannel channel);
+    void deleteNotificationChannelFromAssistant(in INotificationListener token, String pkg, String channelId);
+    ParceledListSlice getNotificationChannelsFromAssistant(in INotificationListener token, String pkg);
 
     ComponentName getEffectsSuppressor();
     boolean matchesCallFilter(in Bundle extras);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index c1e2072..119b055 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3985,19 +3985,6 @@
             return new Builder(builderContext, n);
         }
 
-        private static Class<? extends Style> getNotificationStyleClass(String templateClass) {
-            Class<? extends Style>[] classes = new Class[] {
-                    BigTextStyle.class, BigPictureStyle.class, InboxStyle.class, MediaStyle.class,
-                    DecoratedCustomViewStyle.class, DecoratedMediaCustomViewStyle.class,
-                    MessagingStyle.class };
-            for (Class<? extends Style> innerClass : classes) {
-                if (templateClass.equals(innerClass.getName())) {
-                    return innerClass;
-                }
-            }
-            return null;
-        }
-
         /**
          * @deprecated Use {@link #build()} instead.
          */
@@ -4175,6 +4162,23 @@
     }
 
     /**
+     * @hide
+     */
+    @SystemApi
+    public static Class<? extends Style> getNotificationStyleClass(String templateClass) {
+        Class<? extends Style>[] classes = new Class[] {
+                BigTextStyle.class, BigPictureStyle.class, InboxStyle.class, MediaStyle.class,
+                DecoratedCustomViewStyle.class, DecoratedMediaCustomViewStyle.class,
+                MessagingStyle.class };
+        for (Class<? extends Style> innerClass : classes) {
+            if (templateClass.equals(innerClass.getName())) {
+                return innerClass;
+            }
+        }
+        return null;
+    }
+
+    /**
      * An object that can apply a rich notification style to a {@link Notification.Builder}
      * object.
      */
diff --git a/core/java/android/app/QueuedWork.java b/core/java/android/app/QueuedWork.java
index 6ee4780..0ae8505 100644
--- a/core/java/android/app/QueuedWork.java
+++ b/core/java/android/app/QueuedWork.java
@@ -16,86 +16,197 @@
 
 package android.app;
 
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.LinkedList;
 
 /**
- * Internal utility class to keep track of process-global work that's
- * outstanding and hasn't been finished yet.
+ * Internal utility class to keep track of process-global work that's outstanding and hasn't been
+ * finished yet.
  *
- * This was created for writing SharedPreference edits out
- * asynchronously so we'd have a mechanism to wait for the writes in
- * Activity.onPause and similar places, but we may use this mechanism
- * for other things in the future.
+ * New work will be {@link #queue queued}.
+ *
+ * It is possible to add 'finisher'-runnables that are {@link #waitToFinish guaranteed to be run}.
+ * This is used to make sure the work has been finished.
+ *
+ * This was created for writing SharedPreference edits out asynchronously so we'd have a mechanism
+ * to wait for the writes in Activity.onPause and similar places, but we may use this mechanism for
+ * other things in the future.
+ *
+ * The queued asynchronous work is performed on a separate, dedicated thread.
  *
  * @hide
  */
 public class QueuedWork {
+    private static final String LOG_TAG = QueuedWork.class.getSimpleName();
 
-    // The set of Runnables that will finish or wait on any async
-    // activities started by the application.
-    private static final ConcurrentLinkedQueue<Runnable> sPendingWorkFinishers =
-            new ConcurrentLinkedQueue<Runnable>();
+    /** Delay for delayed runnables */
+    private static final long DELAY = 50;
 
-    private static ExecutorService sSingleThreadExecutor = null; // lazy, guarded by class
+    /** Lock for this class */
+    private static final Object sLock = new Object();
+
+    /** Finishers {@link #addFinisher added} and not yet {@link #removeFinisher removed} */
+    @GuardedBy("sLock")
+    private static final LinkedList<Runnable> sFinishers = new LinkedList<>();
+
+    /** {@link #getHandler() Lazily} created handler */
+    @GuardedBy("sLock")
+    private static Handler sHandler = null;
+
+    /** Work queued via {@link #queue} */
+    @GuardedBy("sLock")
+    private static final LinkedList<Runnable> sWork = new LinkedList<>();
+
+    /** If new work can be delayed or not */
+    @GuardedBy("sLock")
+    private static boolean sCanDelay = true;
 
     /**
-     * Returns a single-thread Executor shared by the entire process,
-     * creating it if necessary.
+     * Lazily create a handler on a separate thread.
+     *
+     * @return the handler
      */
-    public static ExecutorService singleThreadExecutor() {
-        synchronized (QueuedWork.class) {
-            if (sSingleThreadExecutor == null) {
-                // TODO: can we give this single thread a thread name?
-                sSingleThreadExecutor = Executors.newSingleThreadExecutor();
+    private static Handler getHandler() {
+        synchronized (sLock) {
+            if (sHandler == null) {
+                HandlerThread handlerThread = new HandlerThread("queued-work-looper",
+                        Process.THREAD_PRIORITY_BACKGROUND);
+                handlerThread.start();
+
+                sHandler = new QueuedWorkHandler(handlerThread.getLooper());
             }
-            return sSingleThreadExecutor;
+            return sHandler;
         }
     }
 
     /**
-     * Add a runnable to finish (or wait for) a deferred operation
-     * started in this context earlier.  Typically finished by e.g.
-     * an Activity#onPause.  Used by SharedPreferences$Editor#startCommit().
+     * Add a finisher-runnable to wait for {@link #queue asynchronously processed work}.
      *
-     * Note that this doesn't actually start it running.  This is just
-     * a scratch set for callers doing async work to keep updated with
-     * what's in-flight.  In the common case, caller code
-     * (e.g. SharedPreferences) will pretty quickly call remove()
-     * after an add().  The only time these Runnables are run is from
-     * waitToFinish(), below.
+     * Used by SharedPreferences$Editor#startCommit().
+     *
+     * Note that this doesn't actually start it running.  This is just a scratch set for callers
+     * doing async work to keep updated with what's in-flight. In the common case, caller code
+     * (e.g. SharedPreferences) will pretty quickly call remove() after an add(). The only time
+     * these Runnables are run is from {@link #waitToFinish}.
+     *
+     * @param finisher The runnable to add as finisher
      */
-    public static void add(Runnable finisher) {
-        sPendingWorkFinishers.add(finisher);
-    }
-
-    public static void remove(Runnable finisher) {
-        sPendingWorkFinishers.remove(finisher);
+    public static void addFinisher(Runnable finisher) {
+        synchronized (sLock) {
+            sFinishers.add(finisher);
+        }
     }
 
     /**
-     * Finishes or waits for async operations to complete.
-     * (e.g. SharedPreferences$Editor#startCommit writes)
+     * Remove a previously {@link #addFinisher added} finisher-runnable.
      *
-     * Is called from the Activity base class's onPause(), after
-     * BroadcastReceiver's onReceive, after Service command handling,
-     * etc.  (so async work is never lost)
+     * @param finisher The runnable to remove.
+     */
+    public static void removeFinisher(Runnable finisher) {
+        synchronized (sLock) {
+            sFinishers.remove(finisher);
+        }
+    }
+
+    /**
+     * Trigger queued work to be processed immediately. The queued work is processed on a separate
+     * thread asynchronous. While doing that run and process all finishers on this thread. The
+     * finishers can be implemented in a way to check weather the queued work is finished.
+     *
+     * Is called from the Activity base class's onPause(), after BroadcastReceiver's onReceive,
+     * after Service command handling, etc. (so async work is never lost)
      */
     public static void waitToFinish() {
-        Runnable toFinish;
-        while ((toFinish = sPendingWorkFinishers.poll()) != null) {
-            toFinish.run();
+        Handler handler = getHandler();
+
+        synchronized (sLock) {
+            if (handler.hasMessages(QueuedWorkHandler.MSG_RUN)) {
+                // Force the delayed work to be processed now
+                handler.removeMessages(QueuedWorkHandler.MSG_RUN);
+                handler.sendEmptyMessage(QueuedWorkHandler.MSG_RUN);
+            }
+
+            // We should not delay any work as this might delay the finishers
+            sCanDelay = false;
+        }
+
+        try {
+            while (true) {
+                Runnable finisher;
+
+                synchronized (sLock) {
+                    finisher = sFinishers.poll();
+                }
+
+                if (finisher == null) {
+                    break;
+                }
+
+                finisher.run();
+            }
+        } finally {
+            sCanDelay = true;
         }
     }
-    
+
     /**
-     * Returns true if there is pending work to be done.  Note that the
-     * result is out of data as soon as you receive it, so be careful how you
-     * use it.
+     * Queue a work-runnable for processing asynchronously.
+     *
+     * @param work The new runnable to process
+     * @param shouldDelay If the message should be delayed
+     */
+    public static void queue(Runnable work, boolean shouldDelay) {
+        Handler handler = getHandler();
+
+        synchronized (sLock) {
+            sWork.add(work);
+
+            if (shouldDelay && sCanDelay) {
+                handler.sendEmptyMessageDelayed(QueuedWorkHandler.MSG_RUN, DELAY);
+            } else {
+                handler.sendEmptyMessage(QueuedWorkHandler.MSG_RUN);
+            }
+        }
+    }
+
+    /**
+     * @return True iff there is any {@link #queue async work queued}.
      */
     public static boolean hasPendingWork() {
-        return !sPendingWorkFinishers.isEmpty();
+        synchronized (sLock) {
+            return !sWork.isEmpty();
+        }
     }
-    
+
+    private static class QueuedWorkHandler extends Handler {
+        static final int MSG_RUN = 1;
+
+        QueuedWorkHandler(Looper looper) {
+            super(looper);
+        }
+
+        public void handleMessage(Message msg) {
+            if (msg.what == MSG_RUN) {
+                LinkedList<Runnable> work;
+
+                synchronized (sWork) {
+                    work = (LinkedList<Runnable>) sWork.clone();
+                    sWork.clear();
+
+                    // Remove all msg-s as all work will be processed now
+                    removeMessages(MSG_RUN);
+                }
+
+                work.forEach(Runnable::run);
+            }
+        }
+    }
 }
diff --git a/core/java/android/app/RemoteAction.aidl b/core/java/android/app/RemoteAction.aidl
new file mode 100644
index 0000000..2f9f1cc
--- /dev/null
+++ b/core/java/android/app/RemoteAction.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 RemoteAction;
diff --git a/core/java/android/app/RemoteAction.java b/core/java/android/app/RemoteAction.java
new file mode 100644
index 0000000..a37680f
--- /dev/null
+++ b/core/java/android/app/RemoteAction.java
@@ -0,0 +1,159 @@
+/*
+ * 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.annotation.NonNull;
+import android.graphics.drawable.Icon;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.PrintWriter;
+
+/**
+ * Represents a remote action that can be called from another process.  The action can have an
+ * associated visualization including metadata like an icon or title.
+ */
+public final class RemoteAction implements Parcelable {
+
+    /**
+     * Interface definition for a callback to be invoked when an action is invoked.
+     */
+    public interface OnActionListener {
+        /**
+         * Called when the associated action is invoked.
+         *
+         * @param action The action that was invoked.
+         */
+        void onAction(RemoteAction action);
+    }
+
+    private static final String TAG = "RemoteAction";
+
+    private static final int MESSAGE_ACTION_INVOKED = 1;
+
+    private final Icon mIcon;
+    private final CharSequence mTitle;
+    private final CharSequence mContentDescription;
+    private OnActionListener mActionCallback;
+    private final Messenger mMessenger;
+
+    RemoteAction(Parcel in) {
+        mIcon = Icon.CREATOR.createFromParcel(in);
+        mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+        mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+        mMessenger = in.readParcelable(Messenger.class.getClassLoader());
+    }
+
+    public RemoteAction(@NonNull Icon icon, @NonNull CharSequence title,
+            @NonNull CharSequence contentDescription, @NonNull OnActionListener callback) {
+        if (icon == null || title == null || contentDescription == null || callback == null) {
+            throw new IllegalArgumentException("Expected icon, title, content description and " +
+                    "action callback");
+        }
+        mIcon = icon;
+        mTitle = title;
+        mContentDescription = contentDescription;
+        mActionCallback = callback;
+        mMessenger = new Messenger(new Handler() {
+            @Override
+            public void handleMessage(Message msg) {
+                switch (msg.what) {
+                    case MESSAGE_ACTION_INVOKED:
+                        mActionCallback.onAction(RemoteAction.this);
+                        break;
+                }
+            }
+        });
+    }
+
+    /**
+     * Return an icon representing the action.
+     */
+    public @NonNull Icon getIcon() {
+        return mIcon;
+    }
+
+    /**
+     * Return an title representing the action.
+     */
+    public @NonNull CharSequence getTitle() {
+        return mTitle;
+    }
+
+    /**
+     * Return a content description representing the action.
+     */
+    public @NonNull CharSequence getContentDescription() {
+        return mContentDescription;
+    }
+
+    /**
+     * Sends a message that the action was invoked.
+     * @hide
+     */
+    public void sendActionInvoked() {
+        Message m = Message.obtain();
+        m.what = MESSAGE_ACTION_INVOKED;
+        try {
+            mMessenger.send(m);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Could not send action-invoked", e);
+        }
+    }
+
+    @Override
+    public RemoteAction clone() {
+        return new RemoteAction(mIcon, mTitle, mContentDescription, mActionCallback);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        mIcon.writeToParcel(out, 0);
+        TextUtils.writeToParcel(mTitle, out, flags);
+        TextUtils.writeToParcel(mContentDescription, out, flags);
+        out.writeParcelable(mMessenger, flags);
+    }
+
+    public void dump(String prefix, PrintWriter pw) {
+        pw.print(prefix);
+        pw.print("title=" + mTitle);
+        pw.print(" contentDescription=" + mContentDescription);
+        pw.print(" icon=" + mIcon);
+        pw.println();
+    }
+
+    public static final Parcelable.Creator<RemoteAction> CREATOR =
+            new Parcelable.Creator<RemoteAction>() {
+                public RemoteAction createFromParcel(Parcel in) {
+                    return new RemoteAction(in);
+                }
+                public RemoteAction[] newArray(int size) {
+                    return new RemoteAction[size];
+                }
+            };
+}
\ No newline at end of file
diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java
index c5a8288..023b4f3 100644
--- a/core/java/android/app/SharedPreferencesImpl.java
+++ b/core/java/android/app/SharedPreferencesImpl.java
@@ -54,23 +54,34 @@
 final class SharedPreferencesImpl implements SharedPreferences {
     private static final String TAG = "SharedPreferencesImpl";
     private static final boolean DEBUG = false;
+    private static final Object CONTENT = new Object();
 
     // Lock ordering rules:
-    //  - acquire SharedPreferencesImpl.this before EditorImpl.this
-    //  - acquire mWritingToDiskLock before EditorImpl.this
+    //  - acquire SharedPreferencesImpl.mLock before EditorImpl.mLock
+    //  - acquire mWritingToDiskLock before EditorImpl.mLock
 
     private final File mFile;
     private final File mBackupFile;
     private final int mMode;
-
-    private Map<String, Object> mMap;     // guarded by 'this'
-    private int mDiskWritesInFlight = 0;  // guarded by 'this'
-    private boolean mLoaded = false;      // guarded by 'this'
-    private long mStatTimestamp;          // guarded by 'this'
-    private long mStatSize;               // guarded by 'this'
-
+    private final Object mLock = new Object();
     private final Object mWritingToDiskLock = new Object();
-    private static final Object mContent = new Object();
+
+    @GuardedBy("mLock")
+    private Map<String, Object> mMap;
+
+    @GuardedBy("mLock")
+    private int mDiskWritesInFlight = 0;
+
+    @GuardedBy("mLock")
+    private boolean mLoaded = false;
+
+    @GuardedBy("mLock")
+    private long mStatTimestamp;
+
+    @GuardedBy("mLock")
+    private long mStatSize;
+
+    @GuardedBy("mLock")
     private final WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners =
             new WeakHashMap<OnSharedPreferenceChangeListener, Object>();
 
@@ -92,7 +103,7 @@
     }
 
     private void startLoadFromDisk() {
-        synchronized (this) {
+        synchronized (mLock) {
             mLoaded = false;
         }
         new Thread("SharedPreferencesImpl-load") {
@@ -103,7 +114,7 @@
     }
 
     private void loadFromDisk() {
-        synchronized (SharedPreferencesImpl.this) {
+        synchronized (mLock) {
             if (mLoaded) {
                 return;
             }
@@ -138,7 +149,7 @@
             /* ignore */
         }
 
-        synchronized (SharedPreferencesImpl.this) {
+        synchronized (mLock) {
             mLoaded = true;
             if (map != null) {
                 mMap = map;
@@ -147,7 +158,7 @@
             } else {
                 mMap = new HashMap<>();
             }
-            notifyAll();
+            mLock.notifyAll();
         }
     }
 
@@ -156,7 +167,7 @@
     }
 
     void startReloadIfChangedUnexpectedly() {
-        synchronized (this) {
+        synchronized (mLock) {
             // TODO: wait for any pending writes to disk?
             if (!hasFileChangedUnexpectedly()) {
                 return;
@@ -168,7 +179,7 @@
     // Has the file changed out from under us?  i.e. writes that
     // we didn't instigate.
     private boolean hasFileChangedUnexpectedly() {
-        synchronized (this) {
+        synchronized (mLock) {
             if (mDiskWritesInFlight > 0) {
                 // If we know we caused it, it's not unexpected.
                 if (DEBUG) Log.d(TAG, "disk write in flight, not unexpected.");
@@ -188,19 +199,19 @@
             return true;
         }
 
-        synchronized (this) {
+        synchronized (mLock) {
             return mStatTimestamp != stat.st_mtime || mStatSize != stat.st_size;
         }
     }
 
     public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
-        synchronized(this) {
-            mListeners.put(listener, mContent);
+        synchronized(mLock) {
+            mListeners.put(listener, CONTENT);
         }
     }
 
     public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
-        synchronized(this) {
+        synchronized(mLock) {
             mListeners.remove(listener);
         }
     }
@@ -214,14 +225,14 @@
         }
         while (!mLoaded) {
             try {
-                wait();
+                mLock.wait();
             } catch (InterruptedException unused) {
             }
         }
     }
 
     public Map<String, ?> getAll() {
-        synchronized (this) {
+        synchronized (mLock) {
             awaitLoadedLocked();
             //noinspection unchecked
             return new HashMap<String, Object>(mMap);
@@ -230,7 +241,7 @@
 
     @Nullable
     public String getString(String key, @Nullable String defValue) {
-        synchronized (this) {
+        synchronized (mLock) {
             awaitLoadedLocked();
             String v = (String)mMap.get(key);
             return v != null ? v : defValue;
@@ -239,7 +250,7 @@
 
     @Nullable
     public Set<String> getStringSet(String key, @Nullable Set<String> defValues) {
-        synchronized (this) {
+        synchronized (mLock) {
             awaitLoadedLocked();
             Set<String> v = (Set<String>) mMap.get(key);
             return v != null ? v : defValues;
@@ -247,28 +258,28 @@
     }
 
     public int getInt(String key, int defValue) {
-        synchronized (this) {
+        synchronized (mLock) {
             awaitLoadedLocked();
             Integer v = (Integer)mMap.get(key);
             return v != null ? v : defValue;
         }
     }
     public long getLong(String key, long defValue) {
-        synchronized (this) {
+        synchronized (mLock) {
             awaitLoadedLocked();
             Long v = (Long)mMap.get(key);
             return v != null ? v : defValue;
         }
     }
     public float getFloat(String key, float defValue) {
-        synchronized (this) {
+        synchronized (mLock) {
             awaitLoadedLocked();
             Float v = (Float)mMap.get(key);
             return v != null ? v : defValue;
         }
     }
     public boolean getBoolean(String key, boolean defValue) {
-        synchronized (this) {
+        synchronized (mLock) {
             awaitLoadedLocked();
             Boolean v = (Boolean)mMap.get(key);
             return v != null ? v : defValue;
@@ -276,7 +287,7 @@
     }
 
     public boolean contains(String key) {
-        synchronized (this) {
+        synchronized (mLock) {
             awaitLoadedLocked();
             return mMap.containsKey(key);
         }
@@ -290,7 +301,7 @@
         //      context.getSharedPreferences(..).edit().putString(..).apply()
         //
         // ... all without blocking.
-        synchronized (this) {
+        synchronized (mLock) {
             awaitLoadedLocked();
         }
 
@@ -299,70 +310,86 @@
 
     // Return value from EditorImpl#commitToMemory()
     private static class MemoryCommitResult {
-        public long memoryStateGeneration;
-        public List<String> keysModified;  // may be null
-        public Set<OnSharedPreferenceChangeListener> listeners;  // may be null
-        public Map<?, ?> mapToWriteToDisk;
-        public final CountDownLatch writtenToDiskLatch = new CountDownLatch(1);
-        public volatile boolean writeToDiskResult = false;
+        final long memoryStateGeneration;
+        @Nullable final List<String> keysModified;
+        @Nullable final Set<OnSharedPreferenceChangeListener> listeners;
+        final Map<String, Object> mapToWriteToDisk;
+        final CountDownLatch writtenToDiskLatch = new CountDownLatch(1);
 
-        public void setDiskWriteResult(boolean result) {
+        @GuardedBy("mWritingToDiskLock")
+        volatile boolean writeToDiskResult = false;
+
+        private MemoryCommitResult(long memoryStateGeneration, @Nullable List<String> keysModified,
+                @Nullable Set<OnSharedPreferenceChangeListener> listeners,
+                Map<String, Object> mapToWriteToDisk) {
+            this.memoryStateGeneration = memoryStateGeneration;
+            this.keysModified = keysModified;
+            this.listeners = listeners;
+            this.mapToWriteToDisk = mapToWriteToDisk;
+        }
+
+        void setDiskWriteResult(boolean result) {
             writeToDiskResult = result;
             writtenToDiskLatch.countDown();
         }
     }
 
     public final class EditorImpl implements Editor {
+        private final Object mLock = new Object();
+
+        @GuardedBy("mLock")
         private final Map<String, Object> mModified = Maps.newHashMap();
+
+        @GuardedBy("mLock")
         private boolean mClear = false;
 
         public Editor putString(String key, @Nullable String value) {
-            synchronized (this) {
+            synchronized (mLock) {
                 mModified.put(key, value);
                 return this;
             }
         }
         public Editor putStringSet(String key, @Nullable Set<String> values) {
-            synchronized (this) {
+            synchronized (mLock) {
                 mModified.put(key,
                         (values == null) ? null : new HashSet<String>(values));
                 return this;
             }
         }
         public Editor putInt(String key, int value) {
-            synchronized (this) {
+            synchronized (mLock) {
                 mModified.put(key, value);
                 return this;
             }
         }
         public Editor putLong(String key, long value) {
-            synchronized (this) {
+            synchronized (mLock) {
                 mModified.put(key, value);
                 return this;
             }
         }
         public Editor putFloat(String key, float value) {
-            synchronized (this) {
+            synchronized (mLock) {
                 mModified.put(key, value);
                 return this;
             }
         }
         public Editor putBoolean(String key, boolean value) {
-            synchronized (this) {
+            synchronized (mLock) {
                 mModified.put(key, value);
                 return this;
             }
         }
 
         public Editor remove(String key) {
-            synchronized (this) {
+            synchronized (mLock) {
                 mModified.put(key, this);
                 return this;
             }
         }
 
         public Editor clear() {
-            synchronized (this) {
+            synchronized (mLock) {
                 mClear = true;
                 return this;
             }
@@ -379,12 +406,12 @@
                     }
                 };
 
-            QueuedWork.add(awaitCommit);
+            QueuedWork.addFinisher(awaitCommit);
 
             Runnable postWriteRunnable = new Runnable() {
                     public void run() {
                         awaitCommit.run();
-                        QueuedWork.remove(awaitCommit);
+                        QueuedWork.removeFinisher(awaitCommit);
                     }
                 };
 
@@ -399,8 +426,12 @@
 
         // Returns true if any changes were made
         private MemoryCommitResult commitToMemory() {
-            MemoryCommitResult mcr = new MemoryCommitResult();
-            synchronized (SharedPreferencesImpl.this) {
+            long memoryStateGeneration;
+            List<String> keysModified = null;
+            Set<OnSharedPreferenceChangeListener> listeners = null;
+            Map<String, Object> mapToWriteToDisk;
+
+            synchronized (SharedPreferencesImpl.this.mLock) {
                 // We optimistically don't make a deep copy until
                 // a memory commit comes in when we're already
                 // writing to disk.
@@ -411,17 +442,16 @@
                     // noinspection unchecked
                     mMap = new HashMap<String, Object>(mMap);
                 }
-                mcr.mapToWriteToDisk = mMap;
+                mapToWriteToDisk = mMap;
                 mDiskWritesInFlight++;
 
                 boolean hasListeners = mListeners.size() > 0;
                 if (hasListeners) {
-                    mcr.keysModified = new ArrayList<String>();
-                    mcr.listeners =
-                            new HashSet<OnSharedPreferenceChangeListener>(mListeners.keySet());
+                    keysModified = new ArrayList<String>();
+                    listeners = new HashSet<OnSharedPreferenceChangeListener>(mListeners.keySet());
                 }
 
-                synchronized (this) {
+                synchronized (mLock) {
                     boolean changesMade = false;
 
                     if (mClear) {
@@ -455,7 +485,7 @@
 
                         changesMade = true;
                         if (hasListeners) {
-                            mcr.keysModified.add(k);
+                            keysModified.add(k);
                         }
                     }
 
@@ -465,10 +495,11 @@
                         mCurrentMemoryStateGeneration++;
                     }
 
-                    mcr.memoryStateGeneration = mCurrentMemoryStateGeneration;
+                    memoryStateGeneration = mCurrentMemoryStateGeneration;
                 }
             }
-            return mcr;
+            return new MemoryCommitResult(memoryStateGeneration, keysModified, listeners,
+                    mapToWriteToDisk);
         }
 
         public boolean commit() {
@@ -534,7 +565,7 @@
                     synchronized (mWritingToDiskLock) {
                         writeToFile(mcr, isFromSyncCommit);
                     }
-                    synchronized (SharedPreferencesImpl.this) {
+                    synchronized (mLock) {
                         mDiskWritesInFlight--;
                     }
                     if (postWriteRunnable != null) {
@@ -547,7 +578,7 @@
         // the current thread.
         if (isFromSyncCommit) {
             boolean wasEmpty = false;
-            synchronized (SharedPreferencesImpl.this) {
+            synchronized (mLock) {
                 wasEmpty = mDiskWritesInFlight == 1;
             }
             if (wasEmpty) {
@@ -557,10 +588,10 @@
         }
 
         if (DEBUG) {
-            Log.d(TAG, "added " + mcr.memoryStateGeneration + " -> " + mFile.getName());
+            Log.d(TAG, "queued " + mcr.memoryStateGeneration + " -> " + mFile.getName());
         }
 
-        QueuedWork.singleThreadExecutor().execute(writeToDiskRunnable);
+        QueuedWork.queue(writeToDiskRunnable, !isFromSyncCommit);
     }
 
     private static FileOutputStream createFileOutputStream(File file) {
@@ -592,17 +623,17 @@
         if (mFile.exists()) {
             boolean needsWrite = false;
 
-            if (isFromSyncCommit) {
-                // Only need to write if the disk state is older than this commit
-                if (mDiskStateGeneration < mcr.memoryStateGeneration) {
+            // Only need to write if the disk state is older than this commit
+            if (mDiskStateGeneration < mcr.memoryStateGeneration) {
+                if (isFromSyncCommit) {
                     needsWrite = true;
-                }
-            } else {
-                synchronized (this) {
-                    // No need to persist intermediate states. Just wait for the latest state to be
-                    // persisted.
-                    if (mCurrentMemoryStateGeneration == mcr.memoryStateGeneration) {
-                        needsWrite = true;
+                } else {
+                    synchronized (mLock) {
+                        // No need to persist intermediate states. Just wait for the latest state to
+                        // be persisted.
+                        if (mCurrentMemoryStateGeneration == mcr.memoryStateGeneration) {
+                            needsWrite = true;
+                        }
                     }
                 }
             }
@@ -647,7 +678,7 @@
             ContextImpl.setFilePermissionsFromMode(mFile.getPath(), mMode, 0);
             try {
                 final StructStat stat = Os.stat(mFile.getPath());
-                synchronized (this) {
+                synchronized (mLock) {
                     mStatTimestamp = stat.st_mtime;
                     mStatSize = stat.st_size;
                 }
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 67ce342..6bddfba 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -96,6 +96,7 @@
 import android.os.IPowerManager;
 import android.os.IRecoverySystem;
 import android.os.IUserManager;
+import android.os.IncidentManager;
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RecoverySystem;
@@ -115,6 +116,7 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.text.TextClassificationManager;
 import android.util.Log;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
@@ -221,6 +223,13 @@
                 return new HdmiControlManager(IHdmiControlService.Stub.asInterface(b));
             }});
 
+        registerService(Context.TEXT_CLASSIFICATION_SERVICE, TextClassificationManager.class,
+                new StaticServiceFetcher<TextClassificationManager>() {
+            @Override
+            public TextClassificationManager createService() {
+                return new TextClassificationManager();
+            }});
+
         registerService(Context.CLIPBOARD_SERVICE, ClipboardManager.class,
                 new CachedServiceFetcher<ClipboardManager>() {
             @Override
@@ -766,6 +775,13 @@
                 return new ContextHubManager(ctx.getOuterContext(),
                   ctx.mMainThread.getHandler().getLooper());
             }});
+
+        registerService(Context.INCIDENT_SERVICE, IncidentManager.class,
+                new CachedServiceFetcher<IncidentManager>() {
+            @Override
+            public IncidentManager createService(ContextImpl ctx) throws ServiceNotFoundException {
+                return new IncidentManager(ctx);
+            }});
     }
 
     /**
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 39f415e..b641e63 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -44,6 +44,7 @@
 import android.net.ProxyInfo;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Parcelable;
 import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteCallback;
@@ -152,6 +153,7 @@
      * <li>{@link #EXTRA_PROVISIONING_MAIN_COLOR}, optional</li>
      * <li>{@link #EXTRA_PROVISIONING_SKIP_USER_CONSENT}, optional</li>
      * <li>{@link #EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_DISCLAIMERS}, optional</li>
      * </ul>
      *
      * <p>When managed provisioning has completed, broadcasts are sent to the application specified
@@ -233,6 +235,7 @@
      * <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}, optional</li>
      * <li>{@link #EXTRA_PROVISIONING_LOGO_URI}, optional</li>
      * <li>{@link #EXTRA_PROVISIONING_MAIN_COLOR}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_DISCLAIMERS}, optional</li>
      * </ul>
      *
      * <p>When device owner provisioning has completed, an intent of the type
@@ -804,7 +807,7 @@
      * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})</li>
      * </ul>
      *
-     * <p> It is the responsability of the caller to provide an image with a reasonable
+     * <p> It is the responsibility of the caller to provide an image with a reasonable
      * pixed density for the device.
      *
      * <p> If a content: URI is passed, the intent should have the flag
@@ -818,6 +821,58 @@
             "android.app.extra.PROVISIONING_LOGO_URI";
 
     /**
+     * A {@link Bundle}[] extra consisting of list of disclaimer headers and disclaimer contents.
+     * Each {@link Bundle} must have both {@link #EXTRA_PROVISIONING_DISCLAIMER_HEADER}
+     * as disclaimer header, and {@link #EXTRA_PROVISIONING_DISCLAIMER_CONTENT} as disclaimer
+     * content.
+     *
+     * <p> The extra typically contains one disclaimer from the company of mobile device
+     * management application (MDM), and one disclaimer from the organization.
+     *
+     * <p> Call {@link Bundle#putParcelableArray(String, Parcelable[])} to put the {@link Bundle}[]
+     *
+     * <p> Maximum 3 key-value pairs can be specified. The rest will be ignored.
+     *
+     * <p> Use in an intent with action {@link #ACTION_PROVISION_MANAGED_PROFILE} or
+     * {@link #ACTION_PROVISION_MANAGED_DEVICE}
+     */
+    public static final String EXTRA_PROVISIONING_DISCLAIMERS =
+            "android.app.extra.PROVISIONING_DISCLAIMERS";
+
+    /**
+     * A String extra of localized disclaimer header.
+     *
+     * <p> The extra is typically the company name of mobile device management application (MDM)
+     * or the organization name.
+     *
+     * <p> Use in Bundle {@link #EXTRA_PROVISIONING_DISCLAIMERS}
+     */
+    public static final String EXTRA_PROVISIONING_DISCLAIMER_HEADER =
+            "android.app.extra.PROVISIONING_DISCLAIMER_HEADER";
+
+    /**
+     * A {@link Uri} extra pointing to disclaimer content.
+     *
+     * <h5>The following URI schemes are accepted:</h5>
+     * <ul>
+     * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+     * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})</li>
+     * </ul>
+     *
+     * <p> Styled text is supported in the disclaimer content. The content is parsed by
+     * {@link android.text.Html#fromHtml(String)} and displayed in a
+     * {@link android.widget.TextView}.
+     *
+     * <p> If a <code>content:</code> URI is passed, URI is passed, the intent should have the flag
+     * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} and the uri should be added to the
+     * {@link android.content.ClipData} of the intent too.
+     *
+     * <p> Use in Bundle {@link #EXTRA_PROVISIONING_DISCLAIMERS}
+     */
+    public static final String EXTRA_PROVISIONING_DISCLAIMER_CONTENT =
+            "android.app.extra.PROVISIONING_DISCLAIMER_CONTENT";
+
+    /**
      * A boolean extra indicating if user setup should be skipped, for when provisioning is started
      * during setup-wizard.
      *
@@ -1254,8 +1309,8 @@
     /**
      * Result code for {@link checkProvisioningPreCondition}.
      *
-     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_PROFILE} when the device has a device owner
-     * and the user is a system user on a split system user device.
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_PROFILE} when the device the user is a
+     * system user on a split system user device.
      *
      * @hide
      */
@@ -6827,10 +6882,13 @@
     }
 
     /**
+     * Returns whether the device has been provisioned.
+     *
+     * <p>Not for use by third-party applications.
+     *
      * @hide
-     * @return whether {@link android.provider.Settings.Global#DEVICE_PROVISIONED} has ever been set
-     * to 1.
      */
+    @SystemApi
     public boolean isDeviceProvisioned() {
         try {
             return mService.isDeviceProvisioned();
@@ -6840,9 +6898,16 @@
     }
 
     /**
-     * @hide
-     * Writes that the provisioning configuration has been applied.
-     */
+      * Writes that the provisioning configuration has been applied.
+      *
+      * <p>The caller must hold the {@link android.Manifest.permission#MANAGE_USERS}
+      * permission.
+      *
+      * <p>Not for use by third-party applications.
+      *
+      * @hide
+      */
+    @SystemApi
     public void setDeviceProvisioningConfigApplied() {
         try {
             mService.setDeviceProvisioningConfigApplied();
@@ -6852,9 +6917,17 @@
     }
 
     /**
-     * @hide
+     * Returns whether the provisioning configuration has been applied.
+     *
+     * <p>The caller must hold the {@link android.Manifest.permission#MANAGE_USERS} permission.
+     *
+     * <p>Not for use by third-party applications.
+     *
      * @return whether the provisioning configuration has been applied.
+     *
+     * @hide
      */
+    @SystemApi
     public boolean isDeviceProvisioningConfigApplied() {
         try {
             return mService.isDeviceProvisioningConfigApplied();
@@ -7040,7 +7113,7 @@
      * <li>The managed profile is a profile of the user where the device owner is set.
      *     See {@link UserManager#getUserProfiles()}
      * <li>Both users are affiliated.
-     *         STOPSHIP(b/32326223) Add reference to setAffiliationIds here once public.
+     *     See {@link #setAffiliationIds}.
      * </ul>
      */
     public @NonNull List<UserHandle> getBindDeviceAdminTargetUsers(@NonNull ComponentName admin) {
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index a6f2366..1988e42 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -400,7 +400,7 @@
         final int mDisplayId;
         final ViewNode mRoot;
 
-        WindowNode(AssistStructure assist, ViewRootImpl root) {
+        WindowNode(AssistStructure assist, ViewRootImpl root, int flags) {
             View view = root.getView();
             Rect rect = new Rect();
             view.getBoundsOnScreen(rect);
@@ -415,11 +415,22 @@
             if ((root.getWindowFlags()& WindowManager.LayoutParams.FLAG_SECURE) != 0) {
                 // This is a secure window, so it doesn't want a screenshot, and that
                 // means we should also not copy out its view hierarchy.
-                view.onProvideStructure(builder);
+
+                // Must explicitly set which method to calls since View subclasses might
+                // have implemented the deprecated method.
+                if (flags == 0) {
+                    view.onProvideStructure(builder);
+                } else {
+                    view.onProvideStructure(builder, flags);
+                }
                 builder.setAssistBlocked(true);
                 return;
             }
-            view.dispatchProvideStructure(builder);
+            if (flags == 0) {
+                view.dispatchProvideStructure(builder);
+            } else {
+                view.dispatchProvideStructure(builder, flags);
+            }
         }
 
         WindowNode(ParcelTransferReader reader) {
@@ -1351,14 +1362,14 @@
     }
 
     /** @hide */
-    public AssistStructure(Activity activity) {
+    public AssistStructure(Activity activity, int flags) {
         mHaveData = true;
         mActivityComponent = activity.getComponentName();
         ArrayList<ViewRootImpl> views = WindowManagerGlobal.getInstance().getRootViews(
                 activity.getActivityToken());
         for (int i=0; i<views.size(); i++) {
             ViewRootImpl root = views.get(i);
-            mWindowNodes.add(new WindowNode(this, root));
+            mWindowNodes.add(new WindowNode(this, root, flags));
         }
     }
 
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index 342c285..31b2359 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -34,4 +34,6 @@
     boolean isAppInactive(String packageName, int userId);
     void whitelistAppTemporarily(String packageName, long duration, int userId);
     void onCarrierPrivilegedAppsChanged();
+    void reportChooserSelection(String packageName, int userId, String contentType,
+            in String[] annotations, String action);
 }
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index a0da258..ce8b05a 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -86,6 +86,12 @@
         public static final int SHORTCUT_INVOCATION = 8;
 
         /**
+         * An event type denoting that a package was selected by the user for ChooserActivity.
+         * @hide
+         */
+        public static final int CHOOSER_ACTION = 9;
+
+        /**
          * {@hide}
          */
         public String mPackage;
@@ -119,6 +125,27 @@
         public String mShortcutId;
 
         /**
+         * Action type passed to ChooserActivity
+         * Only present for {@link #CHOOSER_ACTION} event types.
+         * {@hide}
+         */
+        public String mAction;
+
+        /**
+         * Content type passed to ChooserActivity.
+         * Only present for {@link #CHOOSER_ACTION} event types.
+         * {@hide}
+         */
+        public String mContentType;
+
+        /**
+         * Content annotations passed to ChooserActivity.
+         * Only present for {@link #CHOOSER_ACTION} event types.
+         * {@hide}
+         */
+        public String[] mContentAnnotations;
+
+        /**
          * The package name of the source of this event.
          */
         public String getPackageName() {
@@ -307,6 +334,11 @@
             case Event.SHORTCUT_INVOCATION:
                 p.writeString(event.mShortcutId);
                 break;
+            case Event.CHOOSER_ACTION:
+                p.writeString(event.mAction);
+                p.writeString(event.mContentType);
+                p.writeStringArray(event.mContentAnnotations);
+                break;
         }
     }
 
@@ -333,6 +365,9 @@
         // Fill out the event-dependant fields.
         eventOut.mConfiguration = null;
         eventOut.mShortcutId = null;
+        eventOut.mAction = null;
+        eventOut.mContentType = null;
+        eventOut.mContentAnnotations = null;
 
         switch (eventOut.mEventType) {
             case Event.CONFIGURATION_CHANGE:
@@ -342,6 +377,11 @@
             case Event.SHORTCUT_INVOCATION:
                 eventOut.mShortcutId = p.readString();
                 break;
+            case Event.CHOOSER_ACTION:
+                eventOut.mAction = p.readString();
+                eventOut.mContentType = p.readString();
+                eventOut.mContentAnnotations = p.createStringArray();
+                break;
         }
     }
 
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index 2937ccc..57f18f1 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -16,8 +16,10 @@
 
 package android.app.usage;
 
+import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.ArrayMap;
 
 /**
  * Contains usage statistics for an app package for a specific
@@ -64,6 +66,11 @@
     /**
      * {@hide}
      */
+    public ArrayMap<String, ArrayMap<String, Integer>> mChooserCounts;
+
+    /**
+     * {@hide}
+     */
     public UsageStats() {
     }
 
@@ -75,6 +82,7 @@
         mTotalTimeInForeground = stats.mTotalTimeInForeground;
         mLaunchCount = stats.mLaunchCount;
         mLastEvent = stats.mLastEvent;
+        mChooserCounts = stats.mChooserCounts;
     }
 
     public String getPackageName() {
@@ -142,6 +150,26 @@
         mEndTimeStamp = Math.max(mEndTimeStamp, right.mEndTimeStamp);
         mTotalTimeInForeground += right.mTotalTimeInForeground;
         mLaunchCount += right.mLaunchCount;
+        if (mChooserCounts == null) {
+            mChooserCounts = right.mChooserCounts;
+        } else if (right.mChooserCounts != null) {
+            final int chooserCountsSize = right.mChooserCounts.size();
+            for (int i = 0; i < chooserCountsSize; i++) {
+                String action = right.mChooserCounts.keyAt(i);
+                ArrayMap<String, Integer> counts = right.mChooserCounts.valueAt(i);
+                if (!mChooserCounts.containsKey(action) || mChooserCounts.get(action) == null) {
+                    mChooserCounts.put(action, counts);
+                    continue;
+                }
+                final int annotationSize = counts.size();
+                for (int j = 0; j < annotationSize; j++) {
+                    String key = counts.keyAt(j);
+                    int rightValue = counts.valueAt(j);
+                    int leftValue = mChooserCounts.get(action).getOrDefault(key, 0);
+                    mChooserCounts.get(action).put(key, leftValue + rightValue);
+                }
+            }
+        }
     }
 
     @Override
@@ -158,6 +186,21 @@
         dest.writeLong(mTotalTimeInForeground);
         dest.writeInt(mLaunchCount);
         dest.writeInt(mLastEvent);
+        Bundle allCounts = new Bundle();
+        if (mChooserCounts != null) {
+            final int chooserCountSize = mChooserCounts.size();
+            for (int i = 0; i < chooserCountSize; i++) {
+                String action = mChooserCounts.keyAt(i);
+                ArrayMap<String, Integer> counts = mChooserCounts.valueAt(i);
+                Bundle currentCounts = new Bundle();
+                final int annotationSize = counts.size();
+                for (int j = 0; j < annotationSize; j++) {
+                    currentCounts.putInt(counts.keyAt(j), counts.valueAt(j));
+                }
+                allCounts.putBundle(action, currentCounts);
+            }
+        }
+        dest.writeBundle(allCounts);
     }
 
     public static final Creator<UsageStats> CREATOR = new Creator<UsageStats>() {
@@ -171,6 +214,25 @@
             stats.mTotalTimeInForeground = in.readLong();
             stats.mLaunchCount = in.readInt();
             stats.mLastEvent = in.readInt();
+            Bundle allCounts = in.readBundle();
+            if (allCounts != null) {
+                stats.mChooserCounts = new ArrayMap<>();
+                for (String action : allCounts.keySet()) {
+                    if (!stats.mChooserCounts.containsKey(action)) {
+                        ArrayMap<String, Integer> newCounts = new ArrayMap<>();
+                        stats.mChooserCounts.put(action, newCounts);
+                    }
+                    Bundle currentCounts = allCounts.getBundle(action);
+                    if (currentCounts != null) {
+                        for (String key : currentCounts.keySet()) {
+                            int value = currentCounts.getInt(key);
+                            if (value > 0) {
+                                stats.mChooserCounts.get(action).put(key, value);
+                            }
+                        }
+                    }
+                }
+            }
             return stats;
         }
 
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 2aeecfa..75a4a53 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -278,4 +278,23 @@
         } catch (RemoteException re) {
         }
     }
+
+    /**
+     * Reports a Chooser action to the UsageStatsManager.
+     *
+     * @param packageName The package name of the app that is selected.
+     * @param userId The user id of who makes the selection.
+     * @param contentType The type of the content, e.g., Image, Video, App.
+     * @param annotations The annotations of the content, e.g., Game, Selfie.
+     * @param action The action type of Intent that invokes ChooserActivity.
+     * {@link UsageEvents}
+     * @hide
+     */
+    public void reportChooserSelection(String packageName, int userId, String contentType,
+                                       String[] annotations, String action) {
+        try {
+            mService.reportChooserSelection(packageName, userId, contentType, annotations, action);
+        } catch (RemoteException re) {
+        }
+    }
 }
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index b0e27a4..6c1e2a9 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -201,6 +201,23 @@
     public static final int STATE_BLE_TURNING_OFF = 16;
 
     /**
+     * Human-readable string helper for AdapterState
+     * @hide
+     */
+    public static String nameForState(@AdapterState int state) {
+        switch(state) {
+            case STATE_OFF: return "OFF";
+            case STATE_TURNING_ON: return "TURNING_ON";
+            case STATE_ON: return "ON";
+            case STATE_TURNING_OFF: return "TURNING_OFF";
+            case STATE_BLE_TURNING_ON: return "BLE_TURNING_ON";
+            case STATE_BLE_ON: return "BLE_ON";
+            case STATE_BLE_TURNING_OFF: return "BLE_TURNING_OFF";
+            default: return "?!?!? (" + state + ")";
+        }
+    }
+
+    /**
      * Activity Action: Show a system activity that requests discoverable mode.
      * This activity will also request the user to turn on Bluetooth if it
      * is not currently enabled.
@@ -658,15 +675,8 @@
     @SystemApi
     public boolean isLeEnabled() {
        final int state = getLeState();
-       if (state == BluetoothAdapter.STATE_ON) {
-           if (DBG) Log.d (TAG, "STATE_ON");
-       } else if (state == BluetoothAdapter.STATE_BLE_ON) {
-           if (DBG) Log.d (TAG, "STATE_BLE_ON");
-       } else {
-           if (DBG) Log.d (TAG, "STATE_OFF");
-           return false;
-       }
-       return true;
+       if (DBG) Log.d(TAG, "isLeEnabled(): " + BluetoothAdapter.nameForState(state));
+       return (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_BLE_ON);
     }
 
     /**
@@ -831,10 +841,10 @@
         if (state == BluetoothAdapter.STATE_BLE_ON
             || state == BluetoothAdapter.STATE_BLE_TURNING_ON
             || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) {
-            if (VDBG) Log.d(TAG, "Consider internal state as OFF");
+            if (VDBG) Log.d(TAG, "Consider " + BluetoothAdapter.nameForState(state) + " state as OFF");
             state = BluetoothAdapter.STATE_OFF;
         }
-        if (VDBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + state);
+        if (VDBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + BluetoothAdapter.nameForState(state));
         return state;
     }
 
@@ -871,12 +881,12 @@
             mServiceLock.readLock().unlock();
         }
 
-        if (VDBG) Log.d(TAG,"getLeState() returning " + state);
+        if (VDBG) Log.d(TAG,"getLeState() returning " + BluetoothAdapter.nameForState(state));
         return state;
     }
 
     boolean getLeAccess() {
-        if(getLeState() == STATE_ON)
+        if (getLeState() == STATE_ON)
             return true;
 
         else if (getLeState() == STATE_BLE_ON)
@@ -914,8 +924,8 @@
      */
     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
     public boolean enable() {
-        if (isEnabled() == true) {
-            if (DBG) Log.d(TAG, "enable(): BT is already enabled..!");
+        if (isEnabled()) {
+            if (DBG) Log.d(TAG, "enable(): BT already enabled!");
             return true;
         }
         try {
@@ -1518,8 +1528,9 @@
                     }
                 }
             }
-        } catch (RemoteException e) {Log.e(TAG, "getSupportedProfiles:", e);}
-
+        } catch (RemoteException e) {
+          Log.e(TAG, "getSupportedProfiles:", e);
+        }
         return supportedProfiles;
     }
 
@@ -1870,34 +1881,6 @@
      * @hide
      */
     public Pair<byte[], byte[]> readOutOfBandData() {
-        if (getState() != STATE_ON) return null;
-        //TODO(BT
-        /*
-        try {
-            byte[] hash;
-            byte[] randomizer;
-
-            byte[] ret = null;
-            mServiceLock.readLock().lock();
-            if (mService != null) mService.readOutOfBandData();
-
-            if (ret  == null || ret.length != 32) return null;
-
-            hash = Arrays.copyOfRange(ret, 0, 16);
-            randomizer = Arrays.copyOfRange(ret, 16, 32);
-
-            if (DBG) {
-                Log.d(TAG, "readOutOfBandData:" + Arrays.toString(hash) +
-                  ":" + Arrays.toString(randomizer));
-            }
-            return new Pair<byte[], byte[]>(hash, randomizer);
-
-        } catch (RemoteException e) {
-            Log.e(TAG, "", e);
-        } finally {
-            mServiceLock.readLock().unlock();
-        }
-        */
         return null;
     }
 
@@ -2051,7 +2034,7 @@
                             if (cb != null) {
                                 cb.onBluetoothServiceUp(bluetoothService);
                             } else {
-                                Log.d(TAG, "onBluetoothServiceUp: cb is null!!!");
+                                Log.d(TAG, "onBluetoothServiceUp: cb is null!");
                             }
                         } catch (Exception e) {
                             Log.e(TAG,"",e);
@@ -2079,7 +2062,7 @@
                             if (cb != null) {
                                 cb.onBluetoothServiceDown();
                             } else {
-                                Log.d(TAG, "onBluetoothServiceDown: cb is null!!!");
+                                Log.d(TAG, "onBluetoothServiceDown: cb is null!");
                             }
                         } catch (Exception e) {
                             Log.e(TAG,"",e);
@@ -2089,7 +2072,7 @@
             }
 
             public void onBrEdrDown() {
-                if (DBG) Log.i(TAG, "onBrEdrDown:");
+                if (VDBG) Log.i(TAG, "onBrEdrDown: " + mService);
             }
     };
 
@@ -2100,7 +2083,7 @@
      */
     public boolean enableNoAutoConnect() {
         if (isEnabled() == true){
-            if (DBG) Log.d(TAG, "enableNoAutoConnect(): BT is already enabled..!");
+            if (DBG) Log.d(TAG, "enableNoAutoConnect(): BT already enabled!");
             return true;
         }
         try {
@@ -2140,22 +2123,6 @@
      */
     public boolean changeApplicationBluetoothState(boolean on,
                                                    BluetoothStateChangeCallback callback) {
-        if (callback == null) return false;
-
-        //TODO(BT)
-        /*
-        try {
-            mServiceLock.readLock().lock();
-            if (mService != null) {
-                return mService.changeApplicationBluetoothState(on, new
-                    StateChangeCallbackWrapper(callback), new Binder());
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "changeBluetoothState", e);
-        } finally {
-            mServiceLock.readLock().unlock();
-        }
-        */
         return false;
     }
 
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index 231dace..c3d6606 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -27,189 +27,25 @@
 import android.util.Slog;
 
 /**
- * Base class for code that will receive intents sent by sendBroadcast().
- *
- * <p>If you don't need to send broadcasts across applications, consider using
- * this class with {@link android.support.v4.content.LocalBroadcastManager} instead
- * of the more general facilities described below.  This will give you a much
- * more efficient implementation (no cross-process communication needed) and allow
- * you to avoid thinking about any security issues related to other applications
- * being able to receive or send your broadcasts.
+ * Base class for code that receives and handles broadcast intents sent by
+ * {@link android.content.Context#sendBroadcast(Intent)}.
  *
  * <p>You can either dynamically register an instance of this class with
  * {@link Context#registerReceiver Context.registerReceiver()}
- * or statically publish an implementation through the
+ * or statically declare an implementation with the
  * {@link android.R.styleable#AndroidManifestReceiver &lt;receiver&gt;}
  * tag in your <code>AndroidManifest.xml</code>.
- * 
- * <p><em><strong>Note:</strong></em>
- * &nbsp;&nbsp;&nbsp;If registering a receiver in your
- * {@link android.app.Activity#onResume() Activity.onResume()}
- * implementation, you should unregister it in 
- * {@link android.app.Activity#onPause() Activity.onPause()}.
- * (You won't receive intents when paused, 
- * and this will cut down on unnecessary system overhead). Do not unregister in 
- * {@link android.app.Activity#onSaveInstanceState(android.os.Bundle) Activity.onSaveInstanceState()},
- * because this won't be called if the user moves back in the history
- * stack.
- * 
- * <p>There are two major classes of broadcasts that can be received:</p>
- * <ul>
- * <li> <b>Normal broadcasts</b> (sent with {@link Context#sendBroadcast(Intent)
- * Context.sendBroadcast}) are completely asynchronous.  All receivers of the
- * broadcast are run in an undefined order, often at the same time.  This is
- * more efficient, but means that receivers cannot use the result or abort
- * APIs included here.
- * <li> <b>Ordered broadcasts</b> (sent with {@link Context#sendOrderedBroadcast(Intent, String)
- * Context.sendOrderedBroadcast}) are delivered to one receiver at a time.
- * As each receiver executes in turn, it can propagate a result to the next
- * receiver, or it can completely abort the broadcast so that it won't be passed
- * to other receivers.  The order receivers run in can be controlled with the
- * {@link android.R.styleable#AndroidManifestIntentFilter_priority
- * android:priority} attribute of the matching intent-filter; receivers with
- * the same priority will be run in an arbitrary order.
- * </ul>
- * 
- * <p>Even in the case of normal broadcasts, the system may in some
- * situations revert to delivering the broadcast one receiver at a time.  In
- * particular, for receivers that may require the creation of a process, only
- * one will be run at a time to avoid overloading the system with new processes.
- * In this situation, however, the non-ordered semantics hold: these receivers still
- * cannot return results or abort their broadcast.</p>
- * 
- * <p>Note that, although the Intent class is used for sending and receiving
- * these broadcasts, the Intent broadcast mechanism here is completely separate
- * from Intents that are used to start Activities with
- * {@link Context#startActivity Context.startActivity()}.
- * There is no way for a BroadcastReceiver
- * to see or capture Intents used with startActivity(); likewise, when
- * you broadcast an Intent, you will never find or start an Activity.
- * These two operations are semantically very different: starting an
- * Activity with an Intent is a foreground operation that modifies what the
- * user is currently interacting with; broadcasting an Intent is a background
- * operation that the user is not normally aware of.
- * 
- * <p>The BroadcastReceiver class (when launched as a component through
- * a manifest's {@link android.R.styleable#AndroidManifestReceiver &lt;receiver&gt;}
- * tag) is an important part of an
- * <a href="{@docRoot}guide/topics/fundamentals.html#lcycles">application's overall lifecycle</a>.</p>
- * 
- * <p>Topics covered here:
- * <ol>
- * <li><a href="#Security">Security</a>
- * <li><a href="#ReceiverLifecycle">Receiver Lifecycle</a>
- * <li><a href="#ProcessLifecycle">Process Lifecycle</a>
- * </ol>
  *
  * <div class="special reference">
  * <h3>Developer Guides</h3>
- * <p>For information about how to use this class to receive and resolve intents, read the
- * <a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent Filters</a>
- * developer guide.</p>
- * </div>
+ * <p>For more information about using BroadcastReceiver, read the
+ * <a href="{@docRoot}guide/components/broadcasts.html">Broadcasts</a> developer guide.</p></div>
  *
- * <a name="Security"></a>
- * <h3>Security</h3>
- *
- * <p>Receivers used with the {@link Context} APIs are by their nature a
- * cross-application facility, so you must consider how other applications
- * may be able to abuse your use of them.  Some things to consider are:
- *
- * <ul>
- * <li><p>The Intent namespace is global.  Make sure that Intent action names and
- * other strings are written in a namespace you own, or else you may inadvertently
- * conflict with other applications.
- * <li><p>When you use {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)},
- * <em>any</em> application may send broadcasts to that registered receiver.  You can
- * control who can send broadcasts to it through permissions described below.
- * <li><p>When you publish a receiver in your application's manifest and specify
- * intent-filters for it, any other application can send broadcasts to it regardless
- * of the filters you specify.  To prevent others from sending to it, make it
- * unavailable to them with <code>android:exported="false"</code>.
- * <li><p>When you use {@link Context#sendBroadcast(Intent)} or related methods,
- * normally any other application can receive these broadcasts.  You can control who
- * can receive such broadcasts through permissions described below.  Alternatively,
- * starting with {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}, you
- * can also safely restrict the broadcast to a single application with
- * {@link Intent#setPackage(String) Intent.setPackage}
- * </ul>
- *
- * <p>None of these issues exist when using
- * {@link android.support.v4.content.LocalBroadcastManager}, since intents
- * broadcast it never go outside of the current process.
- *
- * <p>Access permissions can be enforced by either the sender or receiver
- * of a broadcast.
- *
- * <p>To enforce a permission when sending, you supply a non-null
- * <var>permission</var> argument to
- * {@link Context#sendBroadcast(Intent, String)} or
- * {@link Context#sendOrderedBroadcast(Intent, String, BroadcastReceiver, android.os.Handler, int, String, Bundle)}.
- * Only receivers who have been granted this permission
- * (by requesting it with the
- * {@link android.R.styleable#AndroidManifestUsesPermission &lt;uses-permission&gt;}
- * tag in their <code>AndroidManifest.xml</code>) will be able to receive
- * the broadcast.
- *
- * <p>To enforce a permission when receiving, you supply a non-null
- * <var>permission</var> when registering your receiver -- either when calling
- * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter, String, android.os.Handler)}
- * or in the static
- * {@link android.R.styleable#AndroidManifestReceiver &lt;receiver&gt;}
- * tag in your <code>AndroidManifest.xml</code>.  Only broadcasters who have
- * been granted this permission (by requesting it with the
- * {@link android.R.styleable#AndroidManifestUsesPermission &lt;uses-permission&gt;}
- * tag in their <code>AndroidManifest.xml</code>) will be able to send an
- * Intent to the receiver.
- *
- * <p>See the <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
- * document for more information on permissions and security in general.
- *
- * <a name="ReceiverLifecycle"></a>
- * <h3>Receiver Lifecycle</h3>
- * 
- * <p>A BroadcastReceiver object is only valid for the duration of the call
- * to {@link #onReceive}.  Once your code returns from this function,
- * the system considers the object to be finished and no longer active.
- * 
- * <p>This has important repercussions to what you can do in an
- * {@link #onReceive} implementation: anything that requires asynchronous
- * operation is not available, because you will need to return from the
- * function to handle the asynchronous operation, but at that point the
- * BroadcastReceiver is no longer active and thus the system is free to kill
- * its process before the asynchronous operation completes.
- * 
- * <p>In particular, you may <i>not</i> show a dialog or bind to a service from
- * within a BroadcastReceiver.  For the former, you should instead use the
- * {@link android.app.NotificationManager} API.  For the latter, you can
- * use {@link android.content.Context#startService Context.startService()} to
- * send a command to the service.
- *
- * <a name="ProcessLifecycle"></a>
- * <h3>Process Lifecycle</h3>
- * 
- * <p>A process that is currently executing a BroadcastReceiver (that is,
- * currently running the code in its {@link #onReceive} method) is
- * considered to be a foreground process and will be kept running by the
- * system except under cases of extreme memory pressure.
- * 
- * <p>Once you return from onReceive(), the BroadcastReceiver is no longer
- * active, and its hosting process is only as important as any other application
- * components that are running in it.  This is especially important because if
- * that process was only hosting the BroadcastReceiver (a common case for
- * applications that the user has never or not recently interacted with), then
- * upon returning from onReceive() the system will consider its process
- * to be empty and aggressively kill it so that resources are available for other
- * more important processes.
- * 
- * <p>This means that for longer-running operations you will often use
- * a {@link android.app.Service} in conjunction with a BroadcastReceiver to keep
- * the containing process active for the entire time of your operation.
  */
 public abstract class BroadcastReceiver {
     private PendingResult mPendingResult;
     private boolean mDebugUnregister;
-    
+
     /**
      * State for a result that is pending for a broadcast receiver.  Returned
      * by {@link BroadcastReceiver#goAsync() goAsync()}
@@ -218,7 +54,7 @@
      * terminate; you must call {@link #finish()} once you are done with the
      * broadcast.  This allows you to process the broadcast off of the main
      * thread of your app.
-     * 
+     *
      * <p>Note on threading: the state inside of this class is not itself
      * thread-safe, however you can use it from any thread if you properly
      * sure that you do not have races.  Typically this means you will hand
@@ -232,14 +68,14 @@
         public static final int TYPE_REGISTERED = 1;
         /** @hide */
         public static final int TYPE_UNREGISTERED = 2;
-        
+
         final int mType;
         final boolean mOrderedHint;
         final boolean mInitialStickyHint;
         final IBinder mToken;
         final int mSendingUser;
         final int mFlags;
-        
+
         int mResultCode;
         String mResultData;
         Bundle mResultExtras;
@@ -259,7 +95,7 @@
             mSendingUser = userId;
             mFlags = flags;
         }
-        
+
         /**
          * Version of {@link BroadcastReceiver#setResultCode(int)
          * BroadcastReceiver.setResultCode(int)} for
@@ -331,7 +167,7 @@
             mResultData = data;
             mResultExtras = extras;
         }
-     
+
         /**
          * Version of {@link BroadcastReceiver#getAbortBroadcast()
          * BroadcastReceiver.getAbortBroadcast()} for
@@ -350,7 +186,7 @@
             checkSynchronousHint();
             mAbortBroadcast = true;
         }
-        
+
         /**
          * Version of {@link BroadcastReceiver#clearAbortBroadcast()
          * BroadcastReceiver.clearAbortBroadcast()} for
@@ -359,7 +195,7 @@
         public final void clearAbortBroadcast() {
             mAbortBroadcast = false;
         }
-        
+
         /**
          * Finish the broadcast.  The current result will be sent and the
          * next broadcast will proceed.
@@ -375,16 +211,16 @@
                     // of the list to finish the broadcast, so we don't block this
                     // thread (which may be the main thread) to have it finished.
                     //
-                    // Note that we don't need to use QueuedWork.add() with the
+                    // Note that we don't need to use QueuedWork.addFinisher() with the
                     // runnable, since we know the AM is waiting for us until the
                     // executor gets to it.
-                    QueuedWork.singleThreadExecutor().execute( new Runnable() {
+                    QueuedWork.queue(new Runnable() {
                         @Override public void run() {
                             if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                     "Finishing broadcast after work to component " + mToken);
                             sendFinished(mgr);
                         }
-                    });
+                    }, false);
                 } else {
                     if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                             "Finishing broadcast to component " + mToken);
@@ -397,14 +233,14 @@
                 sendFinished(mgr);
             }
         }
-        
+
         /** @hide */
         public void setExtrasClassLoader(ClassLoader cl) {
             if (mResultExtras != null) {
                 mResultExtras.setClassLoader(cl);
             }
         }
-        
+
         /** @hide */
         public void sendFinished(IActivityManager am) {
             synchronized (this) {
@@ -412,7 +248,7 @@
                     throw new IllegalStateException("Broadcast already finished");
                 }
                 mFinished = true;
-            
+
                 try {
                     if (mResultExtras != null) {
                         mResultExtras.setAllowFds(false);
@@ -448,7 +284,7 @@
             Log.e("BroadcastReceiver", e.getMessage(), e);
         }
     }
-    
+
     public BroadcastReceiver() {
     }
 
@@ -468,14 +304,15 @@
      *
      * <p><b>If this BroadcastReceiver was launched through a &lt;receiver&gt; tag,
      * then the object is no longer alive after returning from this
-     * function.</b>  This means you should not perform any operations that
-     * return a result to you asynchronously -- in particular, for interacting
-     * with services, you should use
-     * {@link Context#startService(Intent)} instead of
-     * {@link Context#bindService(Intent, ServiceConnection, int)}.  If you wish
-     * to interact with a service that is already running, you can use
-     * {@link #peekService}.
-     * 
+     * function.</b> This means you should not perform any operations that
+     * return a result to you asynchronously. If you need to perform any follow up
+     * background work, schedule a {@link android.app.job.JobService} with
+     * {@link android.app.job.JobScheduler}.
+     *
+     * If you wish to interact with a service that is already running and previously
+     * bound using {@link android.content.Context#bindService(Intent, ServiceConnection, int) bindService()},
+     * you can use {@link #peekService}.
+     *
      * <p>The Intent filters used in {@link android.content.Context#registerReceiver}
      * and in application manifests are <em>not</em> guaranteed to be exclusive. They
      * are hints to the operating system about how to find suitable recipients. It is
@@ -483,7 +320,7 @@
      * resolution.  For this reason, {@link #onReceive(Context, Intent) onReceive()}
      * implementations should respond only to known actions, ignoring any unexpected
      * Intents that they may receive.
-     * 
+     *
      * @param context The Context in which the receiver is running.
      * @param intent The Intent being received.
      */
@@ -496,7 +333,7 @@
      * responsive to the broadcast (finishing it within 10s), but does allow
      * the implementation to move work related to it over to another thread
      * to avoid glitching the main UI thread due to disk IO.
-     * 
+     *
      * @return Returns a {@link PendingResult} representing the result of
      * the active broadcast.  The BroadcastRecord itself is no longer active;
      * all data and other interaction must go through {@link PendingResult}
@@ -508,15 +345,20 @@
         mPendingResult = null;
         return res;
     }
-    
+
     /**
-     * Provide a binder to an already-running service.  This method is synchronous
+     * Provide a binder to an already-bound service.  This method is synchronous
      * and will not start the target service if it is not present, so it is safe
      * to call from {@link #onReceive}.
-     * 
+     *
+     * For peekService() to return a non null {@link android.os.IBinder} interface
+     * the service must have published it before. In other words some component
+     * must have called {@link android.content.Context#bindService(Intent, ServiceConnection, int)} on it.
+     *
      * @param myContext The Context that had been passed to {@link #onReceive(Context, Intent)}
-     * @param service The Intent indicating the service you wish to use.  See {@link
-     * Context#startService(Intent)} for more information.
+     * @param service Identifies the already-bound service you wish to use. See
+     * {@link android.content.Context#bindService(Intent, ServiceConnection, int)}
+     * for more information.
      */
     public IBinder peekService(Context myContext, Intent service) {
         IActivityManager am = ActivityManager.getService();
@@ -538,13 +380,13 @@
      * Activity {@link android.app.Activity#RESULT_CANCELED} and
      * {@link android.app.Activity#RESULT_OK} constants, though the
      * actual meaning of this value is ultimately up to the broadcaster.
-     * 
+     *
      * <p class="note">This method does not work with non-ordered broadcasts such
      * as those sent with {@link Context#sendBroadcast(Intent)
      * Context.sendBroadcast}</p>
-     * 
+     *
      * @param code The new result code.
-     * 
+     *
      * @see #setResult(int, String, Bundle)
      */
     public final void setResultCode(int code) {
@@ -554,7 +396,7 @@
 
     /**
      * Retrieve the current result code, as set by the previous receiver.
-     * 
+     *
      * @return int The current result code.
      */
     public final int getResultCode() {
@@ -567,13 +409,13 @@
      * {@link Context#sendOrderedBroadcast(Intent, String)
      * Context.sendOrderedBroadcast}.  This is an arbitrary
      * string whose interpretation is up to the broadcaster.
-     * 
+     *
      * <p><strong>This method does not work with non-ordered broadcasts such
      * as those sent with {@link Context#sendBroadcast(Intent)
      * Context.sendBroadcast}</strong></p>
-     * 
+     *
      * @param data The new result data; may be null.
-     * 
+     *
      * @see #setResult(int, String, Bundle)
      */
     public final void setResultData(String data) {
@@ -584,7 +426,7 @@
     /**
      * Retrieve the current result data, as set by the previous receiver.
      * Often this is null.
-     * 
+     *
      * @return String The current result data; may be null.
      */
     public final String getResultData() {
@@ -599,13 +441,13 @@
      * holding arbitrary data, whose interpretation is up to the
      * broadcaster.  Can be set to null.  Calling this method completely
      * replaces the current map (if any).
-     * 
+     *
      * <p><strong>This method does not work with non-ordered broadcasts such
      * as those sent with {@link Context#sendBroadcast(Intent)
      * Context.sendBroadcast}</strong></p>
-     * 
+     *
      * @param extras The new extra data map; may be null.
-     * 
+     *
      * @see #setResult(int, String, Bundle)
      */
     public final void setResultExtras(Bundle extras) {
@@ -617,11 +459,11 @@
      * Retrieve the current result extra data, as set by the previous receiver.
      * Any changes you make to the returned Map will be propagated to the next
      * receiver.
-     * 
+     *
      * @param makeMap If true then a new empty Map will be made for you if the
      *                current Map is null; if false you should be prepared to
      *                receive a null Map.
-     * 
+     *
      * @return Map The current extras map.
      */
     public final Bundle getResultExtras(boolean makeMap) {
@@ -640,11 +482,11 @@
      * {@link Context#sendOrderedBroadcast(Intent, String)
      * Context.sendOrderedBroadcast}.  All current result data is replaced
      * by the value given to this method.
-     * 
+     *
      * <p><strong>This method does not work with non-ordered broadcasts such
      * as those sent with {@link Context#sendBroadcast(Intent)
      * Context.sendBroadcast}</strong></p>
-     * 
+     *
      * @param code The new result code.  Often uses the
      * Activity {@link android.app.Activity#RESULT_CANCELED} and
      * {@link android.app.Activity#RESULT_OK} constants, though the
@@ -662,11 +504,11 @@
         mPendingResult.mResultData = data;
         mPendingResult.mResultExtras = extras;
     }
- 
+
     /**
      * Returns the flag indicating whether or not this receiver should
      * abort the current broadcast.
-     * 
+     *
      * @return True if the broadcast should be aborted.
      */
     public final boolean getAbortBroadcast() {
@@ -679,10 +521,10 @@
      * {@link Context#sendOrderedBroadcast(Intent, String)
      * Context.sendOrderedBroadcast}.  This will prevent
      * any other broadcast receivers from receiving the broadcast. It will still
-     * call {@link #onReceive} of the BroadcastReceiver that the caller of 
+     * call {@link #onReceive} of the BroadcastReceiver that the caller of
      * {@link Context#sendOrderedBroadcast(Intent, String)
      * Context.sendOrderedBroadcast} passed in.
-     * 
+     *
      * <p><strong>This method does not work with non-ordered broadcasts such
      * as those sent with {@link Context#sendBroadcast(Intent)
      * Context.sendBroadcast}</strong></p>
@@ -691,7 +533,7 @@
         checkSynchronousHint();
         mPendingResult.mAbortBroadcast = true;
     }
-    
+
     /**
      * Clears the flag indicating that this receiver should abort the current
      * broadcast.
@@ -701,7 +543,7 @@
             mPendingResult.mAbortBroadcast = false;
         }
     }
-    
+
     /**
      * Returns true if the receiver is currently processing an ordered
      * broadcast.
@@ -709,7 +551,7 @@
     public final boolean isOrderedBroadcast() {
         return mPendingResult != null ? mPendingResult.mOrderedHint : false;
     }
-    
+
     /**
      * Returns true if the receiver is currently processing the initial
      * value of a sticky broadcast -- that is, the value that was last
@@ -719,7 +561,7 @@
     public final boolean isInitialStickyBroadcast() {
         return mPendingResult != null ? mPendingResult.mInitialStickyHint : false;
     }
-    
+
     /**
      * For internal use, sets the hint about whether this BroadcastReceiver is
      * running in ordered mode.
@@ -727,21 +569,21 @@
     public final void setOrderedHint(boolean isOrdered) {
         // Accidentally left in the SDK.
     }
-    
+
     /**
      * For internal use to set the result data that is active. @hide
      */
     public final void setPendingResult(PendingResult result) {
         mPendingResult = result;
     }
-    
+
     /**
      * For internal use to set the result data that is active. @hide
      */
     public final PendingResult getPendingResult() {
         return mPendingResult;
     }
-    
+
     /** @hide */
     public int getSendingUserId() {
         return mPendingResult.mSendingUser;
@@ -761,19 +603,19 @@
     public final void setDebugUnregister(boolean debug) {
         mDebugUnregister = debug;
     }
-    
+
     /**
      * Return the last value given to {@link #setDebugUnregister}.
      */
     public final boolean getDebugUnregister() {
         return mDebugUnregister;
     }
-    
+
     void checkSynchronousHint() {
         if (mPendingResult == null) {
             throw new IllegalStateException("Call while result is not pending");
         }
-        
+
         // Note that we don't assert when receiving the initial sticky value,
         // since that may have come from an ordered broadcast.  We'll catch
         // them later when the real broadcast happens again.
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 5fa4275..11da8dd 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2747,7 +2747,8 @@
             //@hide: SOUND_TRIGGER_SERVICE,
             SHORTCUT_SERVICE,
             //@hide: CONTEXTHUB_SERVICE,
-            SYSTEM_HEALTH_SERVICE
+            SYSTEM_HEALTH_SERVICE,
+            //@hide: INCIDENT_SERVICE
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ServiceName {}
@@ -3309,6 +3310,15 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a
+     * {@link android.text.TextClassificationManager} for text classification services.
+     *
+     * @see #getSystemService
+     * @see android.text.TextClassificationManager
+     */
+    public static final String TEXT_CLASSIFICATION_SERVICE = "textclassification";
+
+    /**
+     * Use with {@link #getSystemService} to retrieve a
      * {@link android.view.inputmethod.InputMethodManager} for accessing input
      * methods.
      *
@@ -3696,6 +3706,12 @@
     public static final String DEVICE_IDENTIFIERS_SERVICE = "device_identifiers";
 
     /**
+     * Service to report a system health "incident"
+     * @hide
+     */
+    public static final String INCIDENT_SERVICE = "incident";
+
+    /**
      * 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 cda8176..16af5e1 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3226,18 +3226,54 @@
     public static final String
             ACTION_DYNAMIC_SENSOR_CHANGED = "android.intent.action.DYNAMIC_SENSOR_CHANGED";
 
-    /** {@hide} */
+    /**
+     * Deprecated - use {@link #ACTION_FACTORY_RESET} instead.
+     *
+     * {@hide}
+     */
+    @Deprecated
     public static final String ACTION_MASTER_CLEAR = "android.intent.action.MASTER_CLEAR";
 
     /**
-     * Boolean intent extra to be used with {@link ACTION_MASTER_CLEAR} in order to force a factory
-     * reset even if {@link android.os.UserManager.DISALLOW_FACTORY_RESET} is set.
+     * Boolean intent extra to be used with {@link #ACTION_MASTER_CLEAR} in order to force a factory
+     * reset even if {@link android.os.UserManager#DISALLOW_FACTORY_RESET} is set.
+     *
+     * <p>Deprecated - use {@link #EXTRA_FORCE_FACTORY_RESET} instead.
+     *
      * @hide
      */
+    @Deprecated
     public static final String EXTRA_FORCE_MASTER_CLEAR =
             "android.intent.extra.FORCE_MASTER_CLEAR";
 
     /**
+     * A broadcast action to trigger a factory reset.
+     *
+     * <p> The sender must hold the {@link android.Manifest.permission#MASTER_CLEAR} permission.
+     *
+     * <p>Not for use by third-party applications.
+     *
+     * @see #EXTRA_FORCE_MASTER_CLEAR
+     *
+     * {@hide}
+     */
+    @SystemApi
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_FACTORY_RESET = "android.intent.action.FACTORY_RESET";
+
+    /**
+     * Boolean intent extra to be used with {@link #ACTION_MASTER_CLEAR} in order to force a factory
+     * reset even if {@link android.os.UserManager#DISALLOW_FACTORY_RESET} is set.
+     *
+     * <p>Not for use by third-party applications.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_FORCE_FACTORY_RESET =
+            "android.intent.extra.FORCE_FACTORY_RESET";
+
+    /**
      * Broadcast action: report that a settings element is being restored from backup.  The intent
      * contains three extras: EXTRA_SETTING_NAME is a string naming the restored setting,
      * EXTRA_SETTING_NEW_VALUE is the value being restored, and EXTRA_SETTING_PREVIOUS_VALUE
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 2c97ec4..7036f87 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -531,7 +531,7 @@
      * @hide
      */
     public final boolean getAutoVerify() {
-        return ((mVerifyState & STATE_VERIFY_AUTO) == 1);
+        return ((mVerifyState & STATE_VERIFY_AUTO) == STATE_VERIFY_AUTO);
     }
 
     /**
diff --git a/core/java/android/content/pm/IPinItemRequest.aidl b/core/java/android/content/pm/IPinItemRequest.aidl
new file mode 100644
index 0000000..efe2835
--- /dev/null
+++ b/core/java/android/content/pm/IPinItemRequest.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.content.pm;
+
+import android.os.Bundle;
+
+/**
+ * {@hide}
+ */
+interface IPinItemRequest {
+    boolean isValid();
+    boolean accept(in Bundle options);
+}
diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl
index 1bf2ab0..91df8e8 100644
--- a/core/java/android/content/pm/IShortcutService.aidl
+++ b/core/java/android/content/pm/IShortcutService.aidl
@@ -15,6 +15,7 @@
  */
 package android.content.pm;
 
+import android.content.IntentSender;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ShortcutInfo;
 
@@ -41,6 +42,9 @@
 
     boolean updateShortcuts(String packageName, in ParceledListSlice shortcuts, int userId);
 
+    boolean requestPinShortcut(String packageName, in ShortcutInfo shortcut,
+            in IntentSender resultIntent, int userId);
+
     void disableShortcuts(String packageName, in List shortcutIds, CharSequence disabledMessage,
             int disabledMessageResId, int userId);
 
@@ -63,4 +67,6 @@
     byte[] getBackupPayload(int user);
 
     void applyRestore(in byte[] payload, int user);
+
+    boolean isRequestPinShortcutSupported(int user);
 }
\ No newline at end of file
diff --git a/core/java/android/content/pm/IntentFilterVerificationInfo.java b/core/java/android/content/pm/IntentFilterVerificationInfo.java
index f47ad1f..f12abf3 100644
--- a/core/java/android/content/pm/IntentFilterVerificationInfo.java
+++ b/core/java/android/content/pm/IntentFilterVerificationInfo.java
@@ -181,7 +181,7 @@
     }
 
     public String getStatusString() {
-        return getStatusStringFromValue(mMainStatus);
+        return getStatusStringFromValue(((long)mMainStatus) << 32);
     }
 
     public static String getStatusStringFromValue(long val) {
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 7fc8044..5f4bc00 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -19,6 +19,8 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.TestApi;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
@@ -32,11 +34,14 @@
 import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
@@ -69,6 +74,36 @@
     static final String TAG = "LauncherApps";
     static final boolean DEBUG = false;
 
+    /**
+     * Activity Action: For the default launcher to show the confirmation dialog to create
+     * a pinned shortcut.
+     *
+     * <p>See the {@link ShortcutManager} javadoc for details.
+     *
+     * <p>
+     * Use {@link #getPinItemRequest(Intent)} to get a {@link PinItemRequest} object,
+     * and call {@link PinItemRequest#accept(Bundle)}
+     * if the user accepts.  If the user doesn't accept, no further action is required.
+     *
+     * @see #EXTRA_PIN_ITEM_REQUEST
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_CONFIRM_PIN_ITEM =
+            "android.content.pm.action.CONFIRM_PIN_ITEM";
+
+    /**
+     * An extra for {@link #ACTION_CONFIRM_PIN_ITEM} containing a
+     * {@link ShortcutInfo} of the shortcut the publisher app asked to pin.
+     *
+     * <p>A helper function {@link #getPinItemRequest(Intent)} can be used
+     * instead of using this constant directly.
+     *
+     * @see #ACTION_CONFIRM_PIN_ITEM
+     */
+    public static final String EXTRA_PIN_ITEM_REQUEST =
+            "android.content.pm.extra.PIN_ITEM_REQUEST";
+
+
     private Context mContext;
     private ILauncherApps mService;
     private PackageManager mPm;
@@ -655,23 +690,41 @@
                 }
             }
         } else if (shortcut.hasIconResource()) {
-            try {
-                final int resId = shortcut.getIconResourceId();
-                if (resId == 0) {
-                    return null; // Shouldn't happen but just in case.
+            return loadDrawableResourceFromPackage(shortcut.getPackage(),
+                    shortcut.getIconResourceId(), shortcut.getUserHandle(), density);
+        } else if (shortcut.getIcon() != null) {
+            // This happens if a shortcut is pending-approval.
+            final Icon icon = shortcut.getIcon();
+            switch (icon.getType()) {
+                case Icon.TYPE_RESOURCE: {
+                    return loadDrawableResourceFromPackage(shortcut.getPackage(),
+                            icon.getResId(), shortcut.getUserHandle(), density);
                 }
-                final ApplicationInfo ai = getApplicationInfo(shortcut.getPackage(),
-                        /* flags =*/ 0, shortcut.getUserHandle());
-                final Resources res = mContext.getPackageManager().getResourcesForApplication(ai);
-                return res.getDrawableForDensity(resId, density);
-            } catch (NameNotFoundException | Resources.NotFoundException e) {
-                return null;
+                case Icon.TYPE_BITMAP: {
+                    return icon.loadDrawable(mContext);
+                }
+                default:
+                    return null; // Shouldn't happen though.
             }
         } else {
             return null; // Has no icon.
         }
     }
 
+    private Drawable loadDrawableResourceFromPackage(String packageName, int resId,
+            UserHandle user, int density) {
+        try {
+            if (resId == 0) {
+                return null; // Shouldn't happen but just in case.
+            }
+            final ApplicationInfo ai = getApplicationInfo(packageName, /* flags =*/ 0, user);
+            final Resources res = mContext.getPackageManager().getResourcesForApplication(ai);
+            return res.getDrawableForDensity(resId, density);
+        } catch (NameNotFoundException | Resources.NotFoundException e) {
+            return null;
+        }
+    }
+
     /**
      * Returns the shortcut icon with badging appropriate for the profile.
      *
@@ -1064,4 +1117,121 @@
             obtainMessage(MSG_SHORTCUT_CHANGED, info).sendToTarget();
         }
     }
+
+    /**
+     * A helper method to extract a {@link PinItemRequest} set to
+     * the {@link #EXTRA_PIN_ITEM_REQUEST} extra.
+     */
+    public PinItemRequest getPinItemRequest(Intent intent) {
+        return intent.getParcelableExtra(EXTRA_PIN_ITEM_REQUEST);
+    }
+
+    /**
+     * Represents a "pin shortcut" request made by an app, which is sent with
+     * an {@link #ACTION_CONFIRM_PIN_ITEM} intent to the default launcher app.
+     *
+     * @see #EXTRA_PIN_ITEM_REQUEST
+     * @see #getPinItemRequest(Intent)
+     */
+    public static final class PinItemRequest implements Parcelable {
+
+        /** This is a request to pin shortcut. */
+        public static final int REQUEST_TYPE_SHORTCUT = 1;
+
+        @IntDef(value = {REQUEST_TYPE_SHORTCUT})
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface RequestType {}
+
+        private final int mRequestType;
+        private final ShortcutInfo mShortcutInfo;
+        private final IPinItemRequest mInner;
+
+        /**
+         * @hide
+         */
+        public PinItemRequest(@RequestType int requestType, ShortcutInfo shortcutInfo,
+                IPinItemRequest inner) {
+            mRequestType = requestType;
+            mShortcutInfo = shortcutInfo;
+            mInner = inner;
+        }
+
+        /**
+         * Represents the type of a request.  For now {@link #REQUEST_TYPE_SHORTCUT} is the only
+         * valid type.
+         */
+        @RequestType
+        public int getRequestType() {
+            return mRequestType;
+        }
+
+        /**
+         * {@link ShortcutInfo} sent by the requesting app.  Always non-null for a
+         * {@link #REQUEST_TYPE_SHORTCUT} request.
+         */
+        @Nullable
+        public ShortcutInfo getShortcutInfo() {
+            return mShortcutInfo;
+        }
+
+        /**
+         * Return {@code TRUE} if a request is valid -- i.e. {@link #accept(Bundle)} has not been
+         * called, and it has not been canceled.
+         */
+        public boolean isValid() {
+            try {
+                return mInner.isValid();
+            } catch (RemoteException e) {
+                return false;
+            }
+        }
+
+        /**
+         * Called by the receiving launcher app when the user accepts the request.
+         */
+        public boolean accept(@Nullable Bundle options) {
+            try {
+                return mInner.accept(options);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        /**
+         * Same as as {@link #accept(Bundle)} with no options.
+         */
+        public boolean accept() {
+            return accept(/* options= */ null);
+        }
+
+        private PinItemRequest(Parcel source) {
+            final ClassLoader cl = getClass().getClassLoader();
+
+            mRequestType = source.readInt();
+            mShortcutInfo = source.readParcelable(cl);
+            mInner = IPinItemRequest.Stub.asInterface(source.readStrongBinder());
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mRequestType);
+            dest.writeParcelable(mShortcutInfo, flags);
+            dest.writeStrongBinder(mInner.asBinder());
+        }
+
+        public static final Creator<PinItemRequest> CREATOR =
+                new Creator<PinItemRequest>() {
+                    public PinItemRequest createFromParcel(Parcel source) {
+                        return new PinItemRequest(source);
+                    }
+                    public PinItemRequest[] newArray(int size) {
+                        return new PinItemRequest[size];
+                    }
+                };
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+    }
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 4411572..2fbb5b1 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3319,7 +3319,8 @@
      * Grant a runtime permission to an application which the application does not
      * already have. The permission must have been requested by the application.
      * If the application is not allowed to hold the permission, a {@link
-     * java.lang.SecurityException} is thrown.
+     * java.lang.SecurityException} is thrown. If the package or permission is
+     * invalid, a {@link java.lang.IllegalArgumentException} is thrown.
      * <p>
      * <strong>Note: </strong>Using this API requires holding
      * android.permission.GRANT_RUNTIME_PERMISSIONS and if the user id is
@@ -3343,7 +3344,8 @@
      * #grantRuntimePermission(String, String, android.os.UserHandle)}. The
      * permission must have been requested by and granted to the application.
      * If the application is not allowed to hold the permission, a {@link
-     * java.lang.SecurityException} is thrown.
+     * java.lang.SecurityException} is thrown. If the package or permission is
+     * invalid, a {@link java.lang.IllegalArgumentException} is thrown.
      * <p>
      * <strong>Note: </strong>Using this API requires holding
      * android.permission.REVOKE_RUNTIME_PERMISSIONS and if the user id is
@@ -3487,15 +3489,15 @@
     public abstract @Nullable String[] getPackagesForUid(int uid);
 
     /**
-     * Retrieve the official name associated with a user id.  This name is
+     * Retrieve the official name associated with a uid. This name is
      * guaranteed to never change, though it is possible for the underlying
-     * user id to be changed.  That is, if you are storing information about
-     * user ids in persistent storage, you should use the string returned
-     * by this function instead of the raw user-id.
+     * uid to be changed.  That is, if you are storing information about
+     * uids in persistent storage, you should use the string returned
+     * by this function instead of the raw uid.
      *
-     * @param uid The user id for which you would like to retrieve a name.
-     * @return Returns a unique name for the given user id, or null if the
-     * user id is not currently assigned.
+     * @param uid The uid for which you would like to retrieve a name.
+     * @return Returns a unique name for the given uid, or null if the
+     * uid is not currently assigned.
      */
     public abstract @Nullable String getNameForUid(int uid);
 
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index ad0a6b2..1ba68a6 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -197,15 +197,15 @@
             boolean overridePolicy);
 
     /**
-     * Retrieve the official name associated with a user id.  This name is
+     * Retrieve the official name associated with a uid. This name is
      * guaranteed to never change, though it is possible for the underlying
-     * user id to be changed.  That is, if you are storing information about
-     * user ids in persistent storage, you should use the string returned
-     * by this function instead of the raw user-id.
+     * uid to be changed. That is, if you are storing information about
+     * uids in persistent storage, you should use the string returned
+     * by this function instead of the raw uid.
      *
-     * @param uid The user id for which you would like to retrieve a name.
-     * @return Returns a unique name for the given user id, or null if the
-     * user id is not currently assigned.
+     * @param uid The uid for which you would like to retrieve a name.
+     * @return Returns a unique name for the given uid, or null if the
+     * uid is not currently assigned.
      */
     public abstract String getNameForUid(int uid);
 
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index d7c3722..32bf66a 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -357,6 +357,7 @@
         public final int[] splitRevisionCodes;
 
         public final boolean coreApp;
+        public final boolean debuggable;
         public final boolean multiArch;
         public final boolean use32bitAbi;
         public final boolean extractNativeLibs;
@@ -374,6 +375,7 @@
             this.baseRevisionCode = baseApk.revisionCode;
             this.splitRevisionCodes = splitRevisionCodes;
             this.coreApp = baseApk.coreApp;
+            this.debuggable = baseApk.debuggable;
             this.multiArch = baseApk.multiArch;
             this.use32bitAbi = baseApk.use32bitAbi;
             this.extractNativeLibs = baseApk.extractNativeLibs;
@@ -403,6 +405,7 @@
         public final Signature[] signatures;
         public final Certificate[][] certificates;
         public final boolean coreApp;
+        public final boolean debuggable;
         public final boolean multiArch;
         public final boolean use32bitAbi;
         public final boolean extractNativeLibs;
@@ -410,7 +413,8 @@
         public ApkLite(String codePath, String packageName, String splitName, int versionCode,
                 int revisionCode, int installLocation, List<VerifierInfo> verifiers,
                 Signature[] signatures, Certificate[][] certificates, boolean coreApp,
-                boolean multiArch, boolean use32bitAbi, boolean extractNativeLibs) {
+                boolean debuggable, boolean multiArch, boolean use32bitAbi,
+                boolean extractNativeLibs) {
             this.codePath = codePath;
             this.packageName = packageName;
             this.splitName = splitName;
@@ -421,6 +425,7 @@
             this.signatures = signatures;
             this.certificates = certificates;
             this.coreApp = coreApp;
+            this.debuggable = debuggable;
             this.multiArch = multiArch;
             this.use32bitAbi = use32bitAbi;
             this.extractNativeLibs = extractNativeLibs;
@@ -1621,6 +1626,7 @@
         int versionCode = 0;
         int revisionCode = 0;
         boolean coreApp = false;
+        boolean debuggable = false;
         boolean multiArch = false;
         boolean use32bitAbi = false;
         boolean extractNativeLibs = true;
@@ -1660,6 +1666,9 @@
             if (parser.getDepth() == searchDepth && "application".equals(parser.getName())) {
                 for (int i = 0; i < attrs.getAttributeCount(); ++i) {
                     final String attr = attrs.getAttributeName(i);
+                    if ("debuggable".equals(attr)) {
+                        debuggable = attrs.getAttributeBooleanValue(i, false);
+                    }
                     if ("multiArch".equals(attr)) {
                         multiArch = attrs.getAttributeBooleanValue(i, false);
                     }
@@ -1675,7 +1684,7 @@
 
         return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode,
                 revisionCode, installLocation, verifiers, signatures, certificates, coreApp,
-                multiArch, use32bitAbi, extractNativeLibs);
+                debuggable, multiArch, use32bitAbi, extractNativeLibs);
     }
 
     /**
@@ -3780,6 +3789,8 @@
                     ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
         }
 
+        final boolean hasVisibleToEphemeral =
+                sa.hasValue(R.styleable.AndroidManifestActivity_visibleToEphemeral);
         final boolean isEphemeral = ((flags & PARSE_IS_EPHEMERAL) != 0);
         final boolean visibleToEphemeral = isEphemeral
                 || sa.getBoolean(R.styleable.AndroidManifestActivity_visibleToEphemeral, false);
@@ -3818,7 +3829,7 @@
                     return null;
                 }
                 intent.setEphemeral(isEphemeral);
-                intent.setVisibleToEphemeral(visibleToEphemeral);
+                intent.setVisibleToEphemeral(visibleToEphemeral || isWebBrowsableIntent(intent));
                 if (intent.countActions() == 0) {
                     Slog.w(TAG, "No actions in intent filter at "
                             + mArchiveSourcePath + " "
@@ -3826,6 +3837,10 @@
                 } else {
                     a.intents.add(intent);
                 }
+                // adjust activity flags when we implicitly expose it via a browsable filter
+                if (!hasVisibleToEphemeral && intent.isVisibleToEphemeral()) {
+                    a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL;
+                }
             } else if (!receiver && parser.getName().equals("preferred")) {
                 ActivityIntentInfo intent = new ActivityIntentInfo(a);
                 if (!parseIntent(res, parser, false /*allowGlobs*/, false /*allowAutoVerify*/,
@@ -3833,7 +3848,7 @@
                     return null;
                 }
                 intent.setEphemeral(isEphemeral);
-                intent.setVisibleToEphemeral(visibleToEphemeral);
+                intent.setVisibleToEphemeral(visibleToEphemeral || isWebBrowsableIntent(intent));
                 if (intent.countActions() == 0) {
                     Slog.w(TAG, "No actions in preferred at "
                             + mArchiveSourcePath + " "
@@ -3844,6 +3859,10 @@
                     }
                     owner.preferredActivityFilters.add(intent);
                 }
+                // adjust activity flags when we implicitly expose it via a browsable filter
+                if (!hasVisibleToEphemeral && intent.isVisibleToEphemeral()) {
+                    a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL;
+                }
             } else if (parser.getName().equals("meta-data")) {
                 if ((a.metaData = parseMetaData(res, parser, a.metaData,
                         outError)) == null) {
@@ -4084,6 +4103,7 @@
             }
         }
 
+        // TODO add visibleToInstantApp attribute to activity alias
         final boolean isEphemeral = ((flags & PARSE_IS_EPHEMERAL) != 0);
         final boolean visibleToEphemeral = isEphemeral
                 || ((a.info.flags & ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL) != 0);
@@ -4115,9 +4135,14 @@
                             + parser.getPositionDescription());
                 } else {
                     intent.setEphemeral(isEphemeral);
-                    intent.setVisibleToEphemeral(visibleToEphemeral);
+                    intent.setVisibleToEphemeral(visibleToEphemeral
+                            || isWebBrowsableIntent(intent));
                     a.intents.add(intent);
                 }
+                // adjust activity flags when we implicitly expose it via a browsable filter
+                if (intent.isVisibleToEphemeral()) {
+                    a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL;
+                }
             } else if (parser.getName().equals("meta-data")) {
                 if ((a.metaData=parseMetaData(res, parser, a.metaData,
                         outError)) == null) {
@@ -4253,6 +4278,8 @@
                     ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
         }
 
+        final boolean hasVisibleToEphemeral =
+                sa.hasValue(R.styleable.AndroidManifestProvider_visibleToEphemeral);
         final boolean isEphemeral = ((flags & PARSE_IS_EPHEMERAL) != 0);
         final boolean visibleToEphemeral = isEphemeral
                 || sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToEphemeral, false);
@@ -4282,7 +4309,8 @@
         }
         p.info.authority = cpname.intern();
 
-        if (!parseProviderTags(res, parser, isEphemeral, visibleToEphemeral, p, outError)) {
+        if (!parseProviderTags(
+                res, parser, isEphemeral, hasVisibleToEphemeral, visibleToEphemeral, p, outError)) {
             return null;
         }
 
@@ -4290,8 +4318,9 @@
     }
 
     private boolean parseProviderTags(Resources res, XmlResourceParser parser,
-            boolean isEphemeral, boolean visibleToEphemeral, Provider outInfo, String[] outError)
-            throws XmlPullParserException, IOException {
+            boolean isEphemeral, boolean hasVisibleToEphemeral, boolean visibleToEphemeral,
+            Provider outInfo, String[] outError)
+                    throws XmlPullParserException, IOException {
         int outerDepth = parser.getDepth();
         int type;
         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
@@ -4308,8 +4337,12 @@
                     return false;
                 }
                 intent.setEphemeral(isEphemeral);
-                intent.setVisibleToEphemeral(visibleToEphemeral);
+                intent.setVisibleToEphemeral(visibleToEphemeral || isWebBrowsableIntent(intent));
                 outInfo.intents.add(intent);
+                // adjust provider flags when we implicitly expose it via a browsable filter
+                if (!hasVisibleToEphemeral && intent.isVisibleToEphemeral()) {
+                    outInfo.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_EPHEMERAL;
+                }
 
             } else if (parser.getName().equals("meta-data")) {
                 if ((outInfo.metaData=parseMetaData(res, parser,
@@ -4556,6 +4589,8 @@
                     ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
         }
 
+        final boolean hasVisibleToEphemeral =
+                sa.hasValue(R.styleable.AndroidManifestService_visibleToEphemeral);
         final boolean isEphemeral = ((flags & PARSE_IS_EPHEMERAL) != 0);
         final boolean visibleToEphemeral = isEphemeral
                 || sa.getBoolean(R.styleable.AndroidManifestService_visibleToEphemeral, false);
@@ -4591,8 +4626,11 @@
                     return null;
                 }
                 intent.setEphemeral(isEphemeral);
-                intent.setVisibleToEphemeral(visibleToEphemeral);
-
+                intent.setVisibleToEphemeral(visibleToEphemeral || isWebBrowsableIntent(intent));
+                // adjust activity flags when we implicitly expose it via a browsable filter
+                if (!hasVisibleToEphemeral && intent.isVisibleToEphemeral()) {
+                    s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_EPHEMERAL;
+                }
                 s.intents.add(intent);
             } else if (parser.getName().equals("meta-data")) {
                 if ((s.metaData=parseMetaData(res, parser, s.metaData,
@@ -4620,6 +4658,12 @@
         return s;
     }
 
+    private boolean isWebBrowsableIntent(IntentInfo intent) {
+        return intent.hasAction(Intent.ACTION_VIEW)
+                && intent.hasCategory(Intent.CATEGORY_BROWSABLE)
+                && (intent.hasDataScheme("http") || intent.hasDataScheme("https"));
+    }
+
     private boolean parseAllMetaData(Resources res, XmlResourceParser parser, String tag,
             Component<?> outInfo, String[] outError) throws XmlPullParserException, IOException {
         int outerDepth = parser.getDepth();
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 56f914e..a4d8916 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -129,6 +129,10 @@
             | CLONE_REMOVE_RES_NAMES;
 
     /** @hide */
+    public static final int CLONE_REMOVE_FOR_LAUNCHER_APPROVAL = CLONE_REMOVE_INTENT
+            | CLONE_REMOVE_RES_NAMES;
+
+    /** @hide */
     @IntDef(flag = true,
             value = {
                     CLONE_REMOVE_ICON,
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index f7c4d59..c8f00b8 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -16,21 +16,31 @@
 package android.content.pm;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.TestApi;
 import android.annotation.UserIdInt;
 import android.app.Activity;
 import android.app.usage.UsageStatsManager;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentSender;
+import android.os.Binder;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
 
 import java.util.List;
 
 /**
+ * <p><strong>TODO Update the overview to how to use the O new features.</strong></p>
+ *
  * The ShortcutManager manages an app's <em>shortcuts</em>. Shortcuts provide users
  * with quick access to activities other than an app's main activity in the currently-active
  * launcher.  For example,
@@ -618,7 +628,7 @@
      *
      * @throws IllegalStateException when the user is locked.
      */
-    public boolean updateShortcuts(List<ShortcutInfo> shortcutInfoList) {
+    public boolean updateShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) {
         try {
             return mService.updateShortcuts(mContext.getPackageName(),
                     new ParceledListSlice(shortcutInfoList), injectMyUserId());
@@ -815,6 +825,61 @@
     }
 
     /**
+     * Return {@code TRUE} if the default launcher supports
+     * {@link #requestPinShortcut(ShortcutInfo, IntentSender)}.
+     */
+    public boolean isRequestPinShortcutSupported() {
+        try {
+            return mService.isRequestPinShortcutSupported(injectMyUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Request to create a pinned shortcut.  The default launcher will receive this request and
+     * ask the user for approval.  If the user approves it, the shortcut will be created and
+     * {@code resultIntent} will be sent.  Otherwise, no responses will be sent to the caller.
+     *
+     * <p>When a request is denied by the user, the caller app will not get any response.
+     *
+     * <p>Only apps with a foreground activity or a foreground service can call it.  Otherwise
+     * it'll throw {@link IllegalStateException}.
+     *
+     * <p>When an app calls this API when a previous request is still waiting for a response,
+     * the previous request will be canceled.
+     *
+     * @param shortcut New shortcut to pin.  If an app wants to pin an existing (either dynamic
+     *     or manifest) shortcut, then it only needs to have an ID, and other fields don't have to
+     *     be set, in which case, the target shortcut must be enabled.
+     *     If it's a new shortcut, all the mandatory fields, such as a short label, must be
+     *     set.
+     * @param resultIntent If not null, this intent will be sent when the shortcut is pinned.
+     *    Use {@link android.app.PendingIntent#getIntentSender()} to create a {@link IntentSender}.
+     *
+     * @return {@code TRUE} if the launcher supports this feature.  Note the API will return without
+     *    waiting for the user to respond, so getting {@code TRUE} from this API does *not* mean
+     *    the shortcut is pinned.  {@code FALSE} if the launcher doesn't support this feature.
+     *
+     * @see #isRequestPinShortcutSupported()
+     * @see IntentSender
+     * @see android.app.PendingIntent#getIntentSender()
+     *
+     * @throws IllegalArgumentException if a shortcut with the same ID exists and is disabled.
+     * @throws IllegalStateException The caller doesn't have a foreground activity or a foreground
+     * service.
+     */
+    public boolean requestPinShortcut(@NonNull ShortcutInfo shortcut,
+            @Nullable IntentSender resultIntent) {
+        try {
+            return mService.requestPinShortcut(mContext.getPackageName(), shortcut,
+                    resultIntent, injectMyUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Called internally when an app is considered to have come to the foreground
      * even when technically it's not.  This method resets the throttling for this package.
      * For example, when the user sends an "inline reply" on a notification, the system UI will
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index ee1f190..227dc91 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1047,18 +1047,36 @@
             changed |= ActivityInfo.CONFIG_ORIENTATION;
             orientation = delta.orientation;
         }
-        if (getScreenLayoutNoDirection(delta.screenLayout) !=
-                    (SCREENLAYOUT_SIZE_UNDEFINED | SCREENLAYOUT_LONG_UNDEFINED)
-                && (getScreenLayoutNoDirection(screenLayout) !=
-                    getScreenLayoutNoDirection(delta.screenLayout))) {
+
+        if (((delta.screenLayout & SCREENLAYOUT_SIZE_MASK) != SCREENLAYOUT_SIZE_UNDEFINED)
+                && (delta.screenLayout & SCREENLAYOUT_SIZE_MASK)
+                != (screenLayout & SCREENLAYOUT_SIZE_MASK)) {
             changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
-            // We need to preserve the previous layout dir bits if they were defined
-            if ((delta.screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK) == 0) {
-                screenLayout = (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK)|delta.screenLayout;
-            } else {
-                screenLayout = delta.screenLayout;
-            }
+            screenLayout = (screenLayout & ~SCREENLAYOUT_SIZE_MASK)
+                    | (delta.screenLayout & SCREENLAYOUT_SIZE_MASK);
         }
+        if (((delta.screenLayout & SCREENLAYOUT_LONG_MASK) != SCREENLAYOUT_LONG_UNDEFINED)
+                && (delta.screenLayout & SCREENLAYOUT_LONG_MASK)
+                != (screenLayout & SCREENLAYOUT_LONG_MASK)) {
+            changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
+            screenLayout = (screenLayout & ~SCREENLAYOUT_LONG_MASK)
+                    | (delta.screenLayout & SCREENLAYOUT_LONG_MASK);
+        }
+        if (((delta.screenLayout & SCREENLAYOUT_ROUND_MASK) != SCREENLAYOUT_ROUND_UNDEFINED)
+                && (delta.screenLayout & SCREENLAYOUT_ROUND_MASK)
+                != (screenLayout & SCREENLAYOUT_ROUND_MASK)) {
+            changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
+            screenLayout = (screenLayout & ~SCREENLAYOUT_ROUND_MASK)
+                    | (delta.screenLayout & SCREENLAYOUT_ROUND_MASK);
+        }
+        if ((delta.screenLayout & SCREENLAYOUT_COMPAT_NEEDED)
+                != (screenLayout & SCREENLAYOUT_COMPAT_NEEDED)
+                && delta.screenLayout != 0) {
+            changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
+            screenLayout = (screenLayout & ~SCREENLAYOUT_COMPAT_NEEDED)
+                | (delta.screenLayout & SCREENLAYOUT_COMPAT_NEEDED);
+        }
+
         if (delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED)
                 && uiMode != delta.uiMode) {
             changed |= ActivityInfo.CONFIG_UI_MODE;
diff --git a/core/java/android/hardware/CameraStatus.java b/core/java/android/hardware/CameraStatus.java
new file mode 100644
index 0000000..bc97e38
--- /dev/null
+++ b/core/java/android/hardware/CameraStatus.java
@@ -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.
+ */
+
+package android.hardware;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Status information about a camera.
+ *
+ * Contains the name of the camera device, and its current status, one of the
+ * ICameraServiceListener.STATUS_ values.
+ *
+ * @hide
+ */
+public class CameraStatus implements Parcelable {
+    public String cameraId;
+    public int status;
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(cameraId);
+        out.writeInt(status);
+    }
+
+    public void readFromParcel(Parcel in) {
+        cameraId = in.readString();
+        status = in.readInt();
+    }
+
+    public static final Parcelable.Creator<CameraStatus> CREATOR =
+            new Parcelable.Creator<CameraStatus>() {
+        @Override
+        public CameraStatus createFromParcel(Parcel in) {
+            CameraStatus status = new CameraStatus();
+            status.readFromParcel(in);
+
+            return status;
+        }
+
+        @Override
+        public CameraStatus[] newArray(int size) {
+            return new CameraStatus[size];
+        }
+    };
+};
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 145b1d0..e8e989f 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -23,6 +23,7 @@
 import android.hardware.ICameraService;
 import android.hardware.ICameraServiceListener;
 import android.hardware.CameraInfo;
+import android.hardware.CameraStatus;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.legacy.CameraDeviceUserShim;
 import android.hardware.camera2.legacy.LegacyMetadataMapper;
@@ -92,11 +93,7 @@
      */
     @NonNull
     public String[] getCameraIdList() throws CameraAccessException {
-        synchronized (mLock) {
-            // ID list creation handles various known failures in device enumeration, so only
-            // exceptions it'll throw are unexpected, and should be propagated upward.
-            return getOrCreateDeviceIdListLocked().toArray(new String[0]);
-        }
+        return CameraManagerGlobal.get().getCameraIdList();
     }
 
     /**
@@ -218,18 +215,10 @@
         CameraCharacteristics characteristics = null;
 
         synchronized (mLock) {
-            if (!getOrCreateDeviceIdListLocked().contains(cameraId)) {
-                throw new IllegalArgumentException(String.format("Camera id %s does not match any" +
-                        " currently connected camera device", cameraId));
-            }
-
-            int id = Integer.parseInt(cameraId);
-
             /*
              * Get the camera characteristics from the camera service directly if it supports it,
              * otherwise get them from the legacy shim instead.
              */
-
             ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
             if (cameraService == null) {
                 throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
@@ -239,6 +228,8 @@
                 if (!supportsCamera2ApiLocked(cameraId)) {
                     // Legacy backwards compatibility path; build static info from the camera
                     // parameters
+                    int id = Integer.parseInt(cameraId);
+
                     String parameters = cameraService.getLegacyParameters(id);
 
                     CameraInfo info = cameraService.getCameraInfo(id);
@@ -246,7 +237,7 @@
                     characteristics = LegacyMetadataMapper.createCharacteristics(parameters, info);
                 } else {
                     // Normal path: Get the camera characteristics directly from the camera service
-                    CameraMetadataNative info = cameraService.getCameraCharacteristics(id);
+                    CameraMetadataNative info = cameraService.getCameraCharacteristics(cameraId);
 
                     characteristics = new CameraCharacteristics(info);
                 }
@@ -303,14 +294,6 @@
 
             ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
 
-            int id;
-            try {
-                id = Integer.parseInt(cameraId);
-            } catch (NumberFormatException e) {
-                throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: "
-                        + cameraId);
-            }
-
             try {
                 if (supportsCamera2ApiLocked(cameraId)) {
                     // Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
@@ -320,10 +303,18 @@
                             ICameraService.ERROR_DISCONNECTED,
                             "Camera service is currently unavailable");
                     }
-                    cameraUser = cameraService.connectDevice(callbacks, id,
+                    cameraUser = cameraService.connectDevice(callbacks, cameraId,
                             mContext.getOpPackageName(), uid);
                 } else {
                     // Use legacy camera implementation for HAL1 devices
+                    int id;
+                    try {
+                        id = Integer.parseInt(cameraId);
+                    } catch (NumberFormatException e) {
+                        throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: "
+                                + cameraId);
+                    }
+
                     Log.i(TAG, "Using legacy camera HAL.");
                     cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);
                 }
@@ -672,69 +663,6 @@
     }
 
     /**
-     * Return or create the list of currently connected camera devices.
-     *
-     * <p>In case of errors connecting to the camera service, will return an empty list.</p>
-     */
-    private ArrayList<String> getOrCreateDeviceIdListLocked() throws CameraAccessException {
-        if (mDeviceIdList == null) {
-            int numCameras = 0;
-            ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
-            ArrayList<String> deviceIdList = new ArrayList<>();
-
-            // If no camera service, then no devices
-            if (cameraService == null) {
-                return deviceIdList;
-            }
-
-            try {
-                numCameras = cameraService.getNumberOfCameras(CAMERA_TYPE_ALL);
-            } catch(ServiceSpecificException e) {
-                throwAsPublicException(e);
-            } catch (RemoteException e) {
-                // camera service just died - if no camera service, then no devices
-                return deviceIdList;
-            }
-
-            for (int i = 0; i < numCameras; ++i) {
-                // Non-removable cameras use integers starting at 0 for their
-                // identifiers
-                boolean isDeviceSupported = false;
-                try {
-                    CameraMetadataNative info = cameraService.getCameraCharacteristics(i);
-                    if (!info.isEmpty()) {
-                        isDeviceSupported = true;
-                    } else {
-                        throw new AssertionError("Expected to get non-empty characteristics");
-                    }
-                } catch(ServiceSpecificException e) {
-                    // DISCONNECTED means that the HAL reported an low-level error getting the
-                    // device info; ILLEGAL_ARGUMENT means that this devices is not supported.
-                    // Skip listing the device.  Other errors,
-                    // propagate exception onward
-                    if (e.errorCode != ICameraService.ERROR_DISCONNECTED ||
-                            e.errorCode != ICameraService.ERROR_ILLEGAL_ARGUMENT) {
-                        throwAsPublicException(e);
-                    }
-                } catch(RemoteException e) {
-                    // Camera service died - no devices to list
-                    deviceIdList.clear();
-                    return deviceIdList;
-                }
-
-                if (isDeviceSupported) {
-                    deviceIdList.add(String.valueOf(i));
-                } else {
-                    Log.w(TAG, "Error querying camera device " + i + " for listing.");
-                }
-
-            }
-            mDeviceIdList = deviceIdList;
-        }
-        return mDeviceIdList;
-    }
-
-    /**
      * Queries the camera service if it supports the camera2 api directly, or needs a shim.
      *
      * @param cameraId a non-{@code null} camera identifier
@@ -752,8 +680,6 @@
      * @return {@code true} if connecting will work for that device version.
      */
     private boolean supportsCameraApiLocked(String cameraId, int apiVersion) {
-        int id = Integer.parseInt(cameraId);
-
         /*
          * Possible return values:
          * - NO_ERROR => CameraX API is supported
@@ -767,7 +693,7 @@
             // If no camera service, no support
             if (cameraService == null) return false;
 
-            return cameraService.supportsCameraApi(id, apiVersion);
+            return cameraService.supportsCameraApi(cameraId, apiVersion);
         } catch (RemoteException e) {
             // Camera service is now down, no support for any API level
         }
@@ -880,7 +806,10 @@
             }
 
             try {
-                cameraService.addListener(this);
+                CameraStatus[] cameraStatuses = cameraService.addListener(this);
+                for (CameraStatus c : cameraStatuses) {
+                    onStatusChangedLocked(c.status, c.cameraId);
+                }
                 mCameraService = cameraService;
             } catch(ServiceSpecificException e) {
                 // Unexpected failure
@@ -890,6 +819,36 @@
             }
         }
 
+        /**
+         * Get a list of all camera IDs that are at least PRESENT; ignore devices that are
+         * NOT_PRESENT or ENUMERATING, since they cannot be used by anyone.
+         */
+        public String[] getCameraIdList() {
+            String[] cameraIds = null;
+            synchronized(mLock) {
+                // Try to make sure we have an up-to-date list of camera devices.
+                connectCameraServiceLocked();
+
+                int idCount = 0;
+                for (int i = 0; i < mDeviceStatus.size(); i++) {
+                    int status = mDeviceStatus.valueAt(i);
+                    if (status == ICameraServiceListener.STATUS_NOT_PRESENT ||
+                            status == ICameraServiceListener.STATUS_ENUMERATING) continue;
+                    idCount++;
+                }
+                cameraIds = new String[idCount];
+                idCount = 0;
+                for (int i = 0; i < mDeviceStatus.size(); i++) {
+                    int status = mDeviceStatus.valueAt(i);
+                    if (status == ICameraServiceListener.STATUS_NOT_PRESENT ||
+                            status == ICameraServiceListener.STATUS_ENUMERATING) continue;
+                    cameraIds[idCount] = mDeviceStatus.keyAt(i);
+                    idCount++;
+                }
+            }
+            return cameraIds;
+        }
+
         public void setTorchMode(String cameraId, boolean enabled) throws CameraAccessException {
             synchronized(mLock) {
 
@@ -1173,9 +1132,9 @@
          * Callback from camera service notifying the process about camera availability changes
          */
         @Override
-        public void onStatusChanged(int status, int cameraId) throws RemoteException {
+        public void onStatusChanged(int status, String cameraId) throws RemoteException {
             synchronized(mLock) {
-                onStatusChangedLocked(status, String.valueOf(cameraId));
+                onStatusChangedLocked(status, cameraId);
             }
         }
 
diff --git a/core/java/android/hardware/location/GeofenceHardware.java b/core/java/android/hardware/location/GeofenceHardware.java
index f537a77..66dd9fc 100644
--- a/core/java/android/hardware/location/GeofenceHardware.java
+++ b/core/java/android/hardware/location/GeofenceHardware.java
@@ -167,6 +167,7 @@
             mMonitorCallbacks = new HashMap<GeofenceHardwareMonitorCallback,
                     GeofenceHardwareMonitorCallbackWrapper>();
 
+    /** @hide */
     public GeofenceHardware(IGeofenceHardware service) {
         mService = service;
     }
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 3636e4e..ae92457 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -183,6 +183,14 @@
     public static final String USB_DATA_UNLOCKED = "unlocked";
 
     /**
+     * Boolean extra indicating whether the intent represents a change in the usb
+     * configuration (as opposed to a state update).
+     *
+     * {@hide}
+     */
+    public static final String USB_CONFIG_CHANGED = "config_changed";
+
+    /**
      * A placeholder indicating that no USB function is being specified.
      * Used to distinguish between selecting no function vs. the default function in
      * {@link #setCurrentFunction(String)}.
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 0073dde..28e392e 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -87,6 +87,13 @@
      * sent as an extra; it should be consulted to see what kind of
      * connectivity event occurred.
      * <p/>
+     * Apps targeting Android 7.0 (API level 24) and higher do not receive this
+     * broadcast if they declare the broadcast receiver in their manifest. Apps
+     * will still receive broadcasts if they register their
+     * {@link android.content.BroadcastReceiver} with
+     * {@link android.content.Context#registerReceiver Context.registerReceiver()}
+     * and that context is still valid.
+     * <p/>
      * If this is a connection that was the result of failing over from a
      * disconnected network, then the FAILOVER_CONNECTION boolean extra is
      * set to true.
diff --git a/core/java/android/net/INetworkRecommendationProvider.aidl b/core/java/android/net/INetworkRecommendationProvider.aidl
index 5e455d3..052c92c 100644
--- a/core/java/android/net/INetworkRecommendationProvider.aidl
+++ b/core/java/android/net/INetworkRecommendationProvider.aidl
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.net.NetworkKey;
 import android.net.RecommendationRequest;
 import android.os.IRemoteCallback;
 
@@ -38,4 +39,15 @@
     void requestRecommendation(in RecommendationRequest request,
                                in IRemoteCallback callback,
                                int sequence);
+
+    /**
+     * Request scoring for networks.
+     *
+     * Implementations should use {@link NetworkScoreManager#updateScores(ScoredNetwork[])} to
+     * respond to score requests.
+     *
+     * @param networks an array of {@link NetworkKey}s to score
+     * @hide
+     */
+    void requestScores(in NetworkKey[] networks);
 }
\ No newline at end of file
diff --git a/core/java/android/net/INetworkScoreService.aidl b/core/java/android/net/INetworkScoreService.aidl
index 24f4504..932f031 100644
--- a/core/java/android/net/INetworkScoreService.aidl
+++ b/core/java/android/net/INetworkScoreService.aidl
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.net.INetworkScoreCache;
+import android.net.NetworkKey;
 import android.net.RecommendationRequest;
 import android.net.RecommendationResult;
 import android.net.ScoredNetwork;
@@ -87,4 +88,16 @@
      */
     RecommendationResult requestRecommendation(in RecommendationRequest request);
 
+    /**
+     * Request scoring for networks.
+     *
+     * Implementations should delegate to the registered network recommendation provider or
+     * fulfill the request locally if possible.
+     *
+     * @param networks an array of {@link NetworkKey}s to score
+     * @return true if the request was delegated or fulfilled locally, false otherwise
+     * @throws SecurityException if the caller is not the system
+     * @hide
+     */
+    boolean requestScores(in NetworkKey[] networks);
 }
diff --git a/core/java/android/net/NetworkRecommendationProvider.java b/core/java/android/net/NetworkRecommendationProvider.java
index cd2ede8..af5a052c 100644
--- a/core/java/android/net/NetworkRecommendationProvider.java
+++ b/core/java/android/net/NetworkRecommendationProvider.java
@@ -10,6 +10,11 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
+
 /**
  * The base class for implementing a network recommendation provider.
  * @hide
@@ -42,11 +47,21 @@
      *
      * @param request a {@link RecommendationRequest} instance containing additional
      *                request details
-     * @return a {@link RecommendationResult} instance containing the recommended
-     *         network to connect to
+     * @param callback a {@link ResultCallback} instance. When a {@link RecommendationResult} is
+     *                 available it must be passed into
+     *                 {@link ResultCallback#onResult(RecommendationResult)}.
      */
-    public abstract RecommendationResult onRequestRecommendation(RecommendationRequest request);
+    public abstract void onRequestRecommendation(RecommendationRequest request,
+            ResultCallback callback);
 
+    /**
+     * Invoked when network scores have been requested.
+     * <p>
+     * Use {@link NetworkScoreManager#updateScores(ScoredNetwork[])} to respond to score requests.
+     *
+     * @param networks a non-empty array of {@link NetworkKey}s to score.
+     */
+    public abstract void onRequestScores(NetworkKey[] networks);
 
     /**
      * Services that can handle {@link NetworkScoreManager#ACTION_RECOMMEND_NETWORKS} should
@@ -56,8 +71,63 @@
         return mService;
     }
 
+    /**
+     * A callback implementing applications should invoke when a {@link RecommendationResult}
+     * is available.
+     */
+    public static final class ResultCallback {
+        private final IRemoteCallback mCallback;
+        private final int mSequence;
+        private final AtomicBoolean mCallbackRun;
+
+        /**
+         * @hide
+         */
+        @VisibleForTesting
+        public ResultCallback(IRemoteCallback callback, int sequence) {
+            mCallback = callback;
+            mSequence = sequence;
+            mCallbackRun = new AtomicBoolean(false);
+        }
+
+        /**
+         * Run the callback with the available {@link RecommendationResult}.
+         * @param result a {@link RecommendationResult} instance.
+         */
+        public void onResult(RecommendationResult result) {
+            if (!mCallbackRun.compareAndSet(false, true)) {
+                throw new IllegalStateException("The callback cannot be run more than once.");
+            }
+            final Bundle data = new Bundle();
+            data.putInt(EXTRA_SEQUENCE, mSequence);
+            data.putParcelable(EXTRA_RECOMMENDATION_RESULT, result);
+            try {
+                mCallback.sendResult(data);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Callback failed for seq: " + mSequence, e);
+            }
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            ResultCallback that = (ResultCallback) o;
+
+            return mSequence == that.mSequence
+                    && Objects.equals(mCallback, that.mCallback);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mCallback, mSequence);
+        }
+    }
+
     private final class ServiceHandler extends Handler {
         static final int MSG_GET_RECOMMENDATION = 1;
+        static final int MSG_REQUEST_SCORES = 2;
 
         ServiceHandler(Looper looper) {
             super(looper, null /*callback*/, true /*async*/);
@@ -72,16 +142,13 @@
                     final int seq = msg.arg1;
                     final RecommendationRequest request =
                             msg.getData().getParcelable(EXTRA_RECOMMENDATION_REQUEST);
-                    final RecommendationResult result = onRequestRecommendation(request);
-                    final Bundle data = new Bundle();
-                    data.putInt(EXTRA_SEQUENCE, seq);
-                    data.putParcelable(EXTRA_RECOMMENDATION_RESULT, result);
-                    try {
-                        callback.sendResult(data);
-                    } catch (RemoteException e) {
-                        Log.w(TAG, "Callback failed for seq: " + seq, e);
-                    }
+                    final ResultCallback resultCallback = new ResultCallback(callback, seq);
+                    onRequestRecommendation(request, resultCallback);
+                    break;
 
+                case MSG_REQUEST_SCORES:
+                    final NetworkKey[] networks = (NetworkKey[]) msg.obj;
+                    onRequestScores(networks);
                     break;
 
                 default:
@@ -110,5 +177,12 @@
             msg.setData(data);
             msg.sendToTarget();
         }
+
+        @Override
+        public void requestScores(NetworkKey[] networks) throws RemoteException {
+            if (networks != null && networks.length > 0) {
+                mHandler.obtainMessage(ServiceHandler.MSG_REQUEST_SCORES, networks).sendToTarget();
+            }
+        }
     }
 }
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index f081e93..fe9563d 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -52,6 +52,17 @@
     public native static void attachRaFilter(FileDescriptor fd, int packetType) throws SocketException;
 
     /**
+     * Attaches a socket filter that accepts L2-L4 signaling traffic required for IP connectivity.
+     *
+     * This includes: all ARP, ICMPv6 RS/RA/NS/NA messages, and DHCPv4 exchanges.
+     *
+     * @param fd the socket's {@link FileDescriptor}.
+     * @param packetType the hardware address type, one of ARPHRD_*.
+     */
+    public native static void attachControlPacketFilter(FileDescriptor fd, int packetType)
+            throws SocketException;
+
+    /**
      * Configures a socket for receiving ICMPv6 router solicitations and sending advertisements.
      * @param fd the socket's {@link FileDescriptor}.
      * @param ifIndex the interface index.
diff --git a/core/java/android/net/ScoredNetwork.java b/core/java/android/net/ScoredNetwork.java
index 0f3f957..cf81e91 100644
--- a/core/java/android/net/ScoredNetwork.java
+++ b/core/java/android/net/ScoredNetwork.java
@@ -104,7 +104,7 @@
      *     metered.
      */
     public ScoredNetwork(NetworkKey networkKey, RssiCurve rssiCurve, boolean meteredHint) {
-        this(networkKey, rssiCurve, false /* meteredHint */, null /* attributes */);
+        this(networkKey, rssiCurve, meteredHint, null /* attributes */);
     }
 
     /**
diff --git a/core/java/android/net/metrics/ConnectStats.java b/core/java/android/net/metrics/ConnectStats.java
new file mode 100644
index 0000000..3114ff8
--- /dev/null
+++ b/core/java/android/net/metrics/ConnectStats.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 android.net.metrics;
+
+import android.system.OsConstants;
+import android.util.IntArray;
+import android.util.SparseIntArray;
+import com.android.internal.util.TokenBucket;
+import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.ConnectStatistics;
+import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.Pair;
+
+/**
+ * A class that aggregates connect() statistics and helps build
+ * IpConnectivityLogClass.ConnectStatistics instances.
+ *
+ * {@hide}
+ */
+public class ConnectStats {
+    private final static int EALREADY     = OsConstants.EALREADY;
+    private final static int EINPROGRESS  = OsConstants.EINPROGRESS;
+
+    /** How many events resulted in a given errno. */
+    private final SparseIntArray mErrnos = new SparseIntArray();
+    /** Latencies of blocking connects. TODO: add non-blocking connects latencies. */
+    private final IntArray mLatencies = new IntArray();
+    /** TokenBucket for rate limiting latency recording. */
+    private final TokenBucket mLatencyTb;
+    /** Maximum number of latency values recorded. */
+    private final int mMaxLatencyRecords;
+    /** Total count of successful connects. */
+    private int mConnectCount = 0;
+    /** Total count of successful connects with IPv6 socket address. */
+    private int mIpv6ConnectCount = 0;
+
+    public ConnectStats(TokenBucket tb, int maxLatencyRecords) {
+        mLatencyTb = tb;
+        mMaxLatencyRecords = maxLatencyRecords;
+    }
+
+    public ConnectStatistics toProto() {
+        ConnectStatistics stats = new ConnectStatistics();
+        stats.connectCount = mConnectCount;
+        stats.ipv6AddrCount = mIpv6ConnectCount;
+        stats.latenciesMs = mLatencies.toArray();
+        stats.errnosCounters = toPairArrays(mErrnos);
+        return stats;
+    }
+
+    public void addEvent(int errno, int latencyMs, String ipAddr) {
+        if (isSuccess(errno)) {
+            countConnect(ipAddr);
+            countLatency(errno, latencyMs);
+        } else {
+            countError(errno);
+        }
+    }
+
+    private void countConnect(String ipAddr) {
+        mConnectCount++;
+        if (isIPv6(ipAddr)) mIpv6ConnectCount++;
+    }
+
+    private void countLatency(int errno, int ms) {
+        if (isNonBlocking(errno)) {
+            // Ignore connect() on non-blocking sockets
+            return;
+        }
+        if (!mLatencyTb.get()) {
+            // Rate limited
+            return;
+        }
+        if (mLatencies.size() >= mMaxLatencyRecords) {
+            // Hard limit the total number of latency measurements.
+            return;
+        }
+        mLatencies.add(ms);
+    }
+
+    private void countError(int errno) {
+        final int newcount = mErrnos.get(errno, 0) + 1;
+        mErrnos.put(errno, newcount);
+    }
+
+    private static boolean isSuccess(int errno) {
+        return (errno == 0) || isNonBlocking(errno);
+    }
+
+    private static boolean isNonBlocking(int errno) {
+        // On non-blocking TCP sockets, connect() immediately returns EINPROGRESS.
+        // On non-blocking TCP sockets that are connecting, connect() immediately returns EALREADY.
+        return (errno == EINPROGRESS) || (errno == EALREADY);
+    }
+
+    private static boolean isIPv6(String ipAddr) {
+        return ipAddr.contains(":");
+    }
+
+    private static Pair[] toPairArrays(SparseIntArray counts) {
+        final int s = counts.size();
+        Pair[] pairs = new Pair[s];
+        for (int i = 0; i < s; i++) {
+            Pair p = new Pair();
+            p.key = counts.keyAt(i);
+            p.value = counts.valueAt(i);
+            pairs[i] = p;
+        }
+        return pairs;
+    }
+}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 3d5d900..e5aeb4b 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -182,7 +182,7 @@
      * New in version 19:
      *   - Wakelock data (wl) gets current and max times.
      */
-    static final String CHECKIN_VERSION = "19";
+    static final String CHECKIN_VERSION = "20";
 
     /**
      * Old version, we hit 9 and ran out of room, need to remove.
diff --git a/core/java/android/os/DropBoxManager.aidl b/core/java/android/os/DropBoxManager.aidl
index 6474ec2..241e93b 100644
--- a/core/java/android/os/DropBoxManager.aidl
+++ b/core/java/android/os/DropBoxManager.aidl
@@ -16,4 +16,4 @@
 
 package android.os;
 
-parcelable DropBoxManager.Entry;
+parcelable DropBoxManager.Entry cpp_header "android/os/DropBoxManager.h";
diff --git a/core/java/android/os/IIncidentManager.aidl b/core/java/android/os/IIncidentManager.aidl
new file mode 100644
index 0000000..1a76648
--- /dev/null
+++ b/core/java/android/os/IIncidentManager.aidl
@@ -0,0 +1,49 @@
+/**
+ * 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.os.IIncidentReportCompletedListener;
+import android.os.IIncidentReportStatusListener;
+import android.os.IncidentReportArgs;
+
+/**
+  * Binder interface to report system health incidents.
+  * {@hide}
+  */
+oneway interface IIncidentManager {
+
+    /**
+     * Takes a report with the given args, reporting status to the optional listener.
+     *
+     * When the report is completed, the system report listener will be notified.
+     */
+    void reportIncident(in IncidentReportArgs args);
+
+    /**
+     * Takes a report with the given args, reporting status to the optional listener.
+     *
+     * When the report is completed, the system report listener will be notified.
+     */
+    void reportIncidentToStream(in IncidentReportArgs args,
+            @nullable IIncidentReportStatusListener listener,
+            FileDescriptor stream);
+
+    /**
+     * Tell the incident daemon that the android system server is up and running.
+     */
+    void systemRunning();
+}
diff --git a/core/java/android/os/IIncidentReportCompletedListener.aidl b/core/java/android/os/IIncidentReportCompletedListener.aidl
new file mode 100644
index 0000000..2d66bf6
--- /dev/null
+++ b/core/java/android/os/IIncidentReportCompletedListener.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.os;
+
+/**
+  * Listener for incident report status
+  *
+  * {@hide}
+  */
+oneway interface IIncidentReportCompletedListener {
+    /**
+     * Called when there has been an incident report.
+     *
+     * The system service implementing this method should delete or move the file
+     * after it is finished with it.
+     */
+    void onIncidentReport(String filename);
+}
diff --git a/core/java/android/os/IIncidentReportStatusListener.aidl b/core/java/android/os/IIncidentReportStatusListener.aidl
new file mode 100644
index 0000000..7be2ac8
--- /dev/null
+++ b/core/java/android/os/IIncidentReportStatusListener.aidl
@@ -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 android.os;
+
+/**
+  * Listener for incident report status
+  *
+  * {@hide}
+  */
+oneway interface IIncidentReportStatusListener {
+    const int STATUS_STARTING = 1;
+    const int STATUS_FINISHED = 2;
+
+    void onReportStarted();
+
+    void onReportSectionStatus(int section, int status);
+
+    void onReportFinished();
+    void onReportFailed();
+}
diff --git a/core/java/android/os/IncidentManager.java b/core/java/android/os/IncidentManager.java
new file mode 100644
index 0000000..976d594
--- /dev/null
+++ b/core/java/android/os/IncidentManager.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.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.content.Context;
+import android.os.IIncidentManager;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.util.Slog;
+
+/**
+ * Class to take an incident report.
+ *
+ * @hide
+ */
+@SystemApi
+@TestApi
+public class IncidentManager {
+    private static final String TAG = "incident";
+
+    private Context mContext;
+
+    /**
+     * @hide
+     */
+    public IncidentManager(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * Take an incident report and put it in dropbox.
+     */
+    public void reportIncident(IncidentReportArgs args) {
+        final IIncidentManager service = IIncidentManager.Stub.asInterface(
+                ServiceManager.getService("incident"));
+        if (service == null) {
+            Slog.e(TAG, "reportIncident can't find incident binder service");
+            return;
+        }
+
+        try {
+            service.reportIncident(args);
+        } catch (RemoteException ex) {
+            Slog.e(TAG, "reportIncident failed", ex);
+        }
+    }
+
+    /**
+     * Convenience method to trigger an incident report and put it in dropbox.
+     * <p>
+     * The fields that are reported will be looked up in the system setting named by
+     * the settingName parameter.  The setting must match one of these patterns:
+     *      The string "disabled": The report will not be taken.
+     *      The string "all": The report will taken with all sections.
+     *      The string "none": The report will taken with no sections, but with the header.
+     *      A comma separated list of field numbers: The report will have these fields.
+     * <p>
+     * The header parameter will be added as a header for the incident report.  Fill in a
+     * {@link android.util.proto.ProtoOutputStream ProtoOutputStream}, and then call the
+     * {@link android.util.proto.ProtoOutputStream#bytes bytes()} method to retrieve
+     * the encoded data for the header.
+     */
+    public void reportIncident(String settingName, byte[] headerProto) {
+        // Sections
+        String setting = Settings.System.getString(mContext.getContentResolver(), settingName);
+        IncidentReportArgs args;
+        try {
+            args = IncidentReportArgs.parseSetting(setting);
+        } catch (IllegalArgumentException ex) {
+            Slog.w(TAG, "Bad value for incident report setting '" + settingName + "'", ex);
+            return;
+        }
+        if (args == null) {
+            Slog.i(TAG, "Incident report requested but disabled: " + settingName);
+            return;
+        }
+
+        // Header
+        args.addHeader(headerProto);
+
+        // Look up the service
+        final IIncidentManager service = IIncidentManager.Stub.asInterface(
+                ServiceManager.getService("incident"));
+        if (service == null) {
+            Slog.e(TAG, "reportIncident can't find incident binder service");
+            return;
+        }
+
+        // Call the service
+        Slog.i(TAG, "Taking incident report: " + settingName);
+        try {
+            service.reportIncident(args);
+        } catch (RemoteException ex) {
+            Slog.e(TAG, "reportIncident failed", ex);
+        }
+    }
+}
+
diff --git a/core/java/android/os/IncidentReportArgs.aidl b/core/java/android/os/IncidentReportArgs.aidl
new file mode 100644
index 0000000..bbddf59
--- /dev/null
+++ b/core/java/android/os/IncidentReportArgs.aidl
@@ -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.
+ */
+
+package android.os;
+
+parcelable IncidentReportArgs cpp_header "android/os/IncidentReportArgs.h";
+
diff --git a/core/java/android/os/IncidentReportArgs.java b/core/java/android/os/IncidentReportArgs.java
new file mode 100644
index 0000000..ce2ae10
--- /dev/null
+++ b/core/java/android/os/IncidentReportArgs.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.SystemApi;
+import android.annotation.TestApi;
+import android.content.Intent;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.IntArray;
+
+import java.util.ArrayList;
+
+/**
+ * The arguments for an incident report.
+ * {@hide}
+ */
+@SystemApi
+@TestApi
+public final class IncidentReportArgs implements Parcelable {
+
+    private final IntArray mSections = new IntArray();
+    private final ArrayList<byte[]> mHeaders = new ArrayList<byte[]>();
+    private boolean mAll;
+
+    /**
+     * Construct an incident report args with no fields.
+     */
+    public IncidentReportArgs() {
+    }
+
+    /**
+     * Construct an incdent report args from the given parcel.
+     */
+    public IncidentReportArgs(Parcel in) {
+        readFromParcel(in);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mAll ? 1 : 0);
+
+        int N = mSections.size();
+        out.writeInt(N);
+        for (int i=0; i<N; i++) {
+            out.writeInt(mSections.get(i));
+        }
+
+        N = mHeaders.size();
+        out.writeInt(N);
+        for (int i=0; i<N; i++) {
+            out.writeByteArray(mHeaders.get(i));
+        }
+    }
+
+    public void readFromParcel(Parcel in) {
+        mAll = in.readInt() != 0;
+
+        mSections.clear();
+        int N = in.readInt();
+        for (int i=0; i<N; i++) {
+            mSections.add(in.readInt());
+        }
+
+        mHeaders.clear();
+        N = in.readInt();
+        for (int i=0; i<N; i++) {
+            mHeaders.add(in.createByteArray());
+        }
+    }
+
+    public static final Parcelable.Creator<IncidentReportArgs> CREATOR
+            = new Parcelable.Creator<IncidentReportArgs>() {
+        public IncidentReportArgs createFromParcel(Parcel in) {
+            return new IncidentReportArgs(in);
+        }
+
+        public IncidentReportArgs[] newArray(int size) {
+            return new IncidentReportArgs[size];
+        }
+    };
+
+    /**
+     * Print this report as a string.
+     */
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("Incident(");
+        if (mAll) {
+            sb.append("all");
+        } else {
+            final int N = mSections.size();
+            if (N > 0) {
+                sb.append(mSections.get(0));
+            }
+            for (int i=1; i<N; i++) {
+                sb.append(" ");
+                sb.append(mSections.get(i));
+            }
+        }
+        sb.append(", ");
+        sb.append(mHeaders.size());
+        sb.append(" headers)");
+        return sb.toString();
+    }
+
+    /**
+     * Set this incident report to include all fields.
+     */
+    public void setAll(boolean all) {
+        mAll = all;
+        if (all) {
+            mSections.clear();
+        }
+    }
+
+    /**
+     * Add this section to the incident report.
+     */
+    public void addSection(int section) {
+        if (!mAll) {
+            mSections.add(section);
+        }
+    }
+
+    /**
+     * Returns whether the incident report will include all fields.
+     */
+    public boolean isAll() {
+        return mAll;
+    }
+
+    /**
+     * Returns whether this section will be included in the incident report.
+     */
+    public boolean containsSection(int section) {
+        return mAll || mSections.indexOf(section) >= 0;
+    }
+
+    public int sectionCount() {
+        return mSections.size();
+    }
+
+    public void addHeader(byte[] header) {
+        mHeaders.add(header);
+    }
+
+    /**
+     * Parses an incident report config as described in the system setting.
+     *
+     * @see IncidentManager#reportIncident
+     */
+    public static IncidentReportArgs parseSetting(String setting)
+            throws IllegalArgumentException {
+        if (setting == null || setting.length() == 0) {
+            return null;
+        }
+        setting = setting.trim();
+        if (setting.length() == 0 || "disabled".equals(setting)) {
+            return null;
+        }
+
+        final IncidentReportArgs args = new IncidentReportArgs();
+
+        if ("all".equals(setting)) {
+            args.setAll(true);
+            return args;
+        } else if ("none".equals(setting)) {
+            return args;
+        }
+
+        final String[] splits = setting.split(",");
+        final int N = splits.length;
+        for (int i=0; i<N; i++) {
+            final String str = splits[i].trim();
+            if (str.length() == 0) {
+                continue;
+            }
+            int section;
+            try {
+                section = Integer.parseInt(str);
+            } catch (NumberFormatException ex) {
+                throw new IllegalArgumentException("Malformed setting. Bad integer at section"
+                        + " index " + i + ": section='" + str + "' setting='" + setting + "'");
+            }
+            if (section < 1) {
+                throw new IllegalArgumentException("Malformed setting. Illegal section at"
+                        + " index " + i + ": section='" + str + "' setting='" + setting + "'");
+            }
+            args.addSection(section);
+        }
+
+        return args;
+    }
+}
+
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 8d4d0a5..9d04929 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -421,6 +421,12 @@
     public static final String REBOOT_SAFE_MODE = "safemode";
 
     /**
+     * The 'reason' value used when rebooting the device without turning on the screen.
+     * @hide
+     */
+    public static final String REBOOT_QUIESCENT = "quiescent";
+
+    /**
      * The value to pass as the 'reason' argument to android_reboot().
      * @hide
      */
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 4eee854..9cd1a42 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -398,6 +398,10 @@
      * make easily identifyable processes even if you are using the same base
      * <var>processClass</var> to start them.
      * 
+     * When invokeWith is not null, the process will be started as a fresh app
+     * and not a zygote fork. Note that this is only allowed for uid 0 or when
+     * debugFlags contains DEBUG_ENABLE_DEBUGGER.
+     *
      * @param processClass The class to use as the process's main entry
      *                     point.
      * @param niceName A more readable name to use for the process.
@@ -410,6 +414,7 @@
      * @param abi non-null the ABI this app should be started with.
      * @param instructionSet null-ok the instruction set to use.
      * @param appDataDir null-ok the data directory of the app.
+     * @param invokeWith null-ok the command to invoke with.
      * @param zygoteArgs Additional arguments to supply to the zygote process.
      * 
      * @return An object that describes the result of the attempt to start the process.
@@ -426,10 +431,11 @@
                                   String abi,
                                   String instructionSet,
                                   String appDataDir,
+                                  String invokeWith,
                                   String[] zygoteArgs) {
         return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                     debugFlags, mountExternal, targetSdkVersion, seInfo,
-                    abi, instructionSet, appDataDir, zygoteArgs);
+                    abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
     }
 
     /** @hide */
@@ -442,10 +448,11 @@
                                   String abi,
                                   String instructionSet,
                                   String appDataDir,
+                                  String invokeWith,
                                   String[] zygoteArgs) {
         return WebViewZygote.getProcess().start(processClass, niceName, uid, gid, gids,
                     debugFlags, mountExternal, targetSdkVersion, seInfo,
-                    abi, instructionSet, appDataDir, zygoteArgs);
+                    abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
     }
 
     /**
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index 6a751e8..78820b5 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -86,7 +86,7 @@
      */
     public static String get(String key) {
         if (key.length() > PROP_NAME_MAX) {
-            throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
+            throw newKeyTooLargeException(key);
         }
         if (TRACK_KEY_ACCESS) onKeyAccess(key);
         return native_get(key);
@@ -99,7 +99,7 @@
      */
     public static String get(String key, String def) {
         if (key.length() > PROP_NAME_MAX) {
-            throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
+            throw newKeyTooLargeException(key);
         }
         if (TRACK_KEY_ACCESS) onKeyAccess(key);
         return native_get(key, def);
@@ -115,7 +115,7 @@
      */
     public static int getInt(String key, int def) {
         if (key.length() > PROP_NAME_MAX) {
-            throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
+            throw newKeyTooLargeException(key);
         }
         if (TRACK_KEY_ACCESS) onKeyAccess(key);
         return native_get_int(key, def);
@@ -131,7 +131,7 @@
      */
     public static long getLong(String key, long def) {
         if (key.length() > PROP_NAME_MAX) {
-            throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
+            throw newKeyTooLargeException(key);
         }
         if (TRACK_KEY_ACCESS) onKeyAccess(key);
         return native_get_long(key, def);
@@ -152,7 +152,7 @@
      */
     public static boolean getBoolean(String key, boolean def) {
         if (key.length() > PROP_NAME_MAX) {
-            throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
+            throw newKeyTooLargeException(key);
         }
         if (TRACK_KEY_ACCESS) onKeyAccess(key);
         return native_get_boolean(key, def);
@@ -165,11 +165,10 @@
      */
     public static void set(String key, String val) {
         if (key.length() > PROP_NAME_MAX) {
-            throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
+            throw newKeyTooLargeException(key);
         }
         if (val != null && val.length() > PROP_VALUE_MAX) {
-            throw new IllegalArgumentException("val.length > " +
-                PROP_VALUE_MAX);
+            throw newValueTooLargeException(key, val);
         }
         if (TRACK_KEY_ACCESS) onKeyAccess(key);
         native_set(key, val);
@@ -197,6 +196,16 @@
         }
     }
 
+    private static IllegalArgumentException newKeyTooLargeException(String key) {
+        return new IllegalArgumentException("system property key '" + key + "' is longer than "
+                + PROP_NAME_MAX + " characters");
+    }
+
+    private static IllegalArgumentException newValueTooLargeException(String key, String value) {
+        return new IllegalArgumentException("value of system property '" + key + "' is longer than "
+                + PROP_VALUE_MAX + " characters: " + value);
+    }
+
     /*
      * Notifies listeners that a system property has changed
      */
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 7e8cc0b..6c01b36 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -85,6 +85,8 @@
     public static final long TRACE_TAG_DATABASE = 1L << 20;
     /** @hide */
     public static final long TRACE_TAG_NETWORK = 1L << 21;
+    /** @hide */
+    public static final long TRACE_TAG_ADB = 1L << 22;
 
     private static final long TRACE_TAG_NOT_READY = 1L << 63;
     private static final int MAX_SECTION_NAME_LEN = 127;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 0d3b328..0a32f0d 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -253,6 +253,20 @@
     public static final String DISALLOW_REMOVE_USER = "no_remove_user";
 
     /**
+     * Specifies if managed profiles of this user can be removed, other than by its profile owner.
+     * The default value is <code>false</code>.
+     * <p>
+     * This restriction can only be set by device owners.
+     *
+     * <p>Key for user restrictions.
+     * <p>Type: Boolean
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_REMOVE_MANAGED_PROFILE = "no_remove_managed_profile";
+
+    /**
      * Specifies if a user is disallowed from enabling or
      * accessing debugging features. The default value is <code>false</code>.
      *
@@ -322,8 +336,8 @@
     public static final String DISALLOW_FACTORY_RESET = "no_factory_reset";
 
     /**
-     * Specifies if a user is disallowed from adding new users and
-     * profiles. This can only be set by device owners and profile owners on the primary user.
+     * Specifies if a user is disallowed from adding new users. This can only be set by device
+     * owners and profile owners on the primary user.
      * The default value is <code>false</code>.
      * <p>This restriction has no effect on secondary users and managed profiles since only the
      * primary user can add other users.
@@ -337,6 +351,20 @@
     public static final String DISALLOW_ADD_USER = "no_add_user";
 
     /**
+     * Specifies if a user is disallowed from adding managed profiles.
+     * <p>The default value for an unmanaged user is <code>false</code>.
+     * For users with a device owner set, the default is <code>true</code>
+     * <p>This restriction can only be set by device owners.
+     *
+     * <p>Key for user restrictions.
+     * <p>Type: Boolean
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_ADD_MANAGED_PROFILE = "no_add_managed_profile";
+
+    /**
      * Specifies if a user is disallowed from disabling application
      * verification. The default value is <code>false</code>.
      *
@@ -634,11 +662,14 @@
      * <code>false</code>. Setting this restriction has no effect if the bootloader is already
      * unlocked.
      *
+     * <p>Not for use by third-party applications.
+     *
      * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
      * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      * @hide
      */
+    @SystemApi
     public static final String DISALLOW_OEM_UNLOCK = "no_oem_unlock";
 
     /**
@@ -1403,7 +1434,7 @@
 
     /**
      * Similar to {@link #createProfileForUser(String, int, int, String[])}
-     * except bypassing the checking of {@link UserManager#DISALLOW_ADD_USER}.
+     * except bypassing the checking of {@link UserManager#DISALLOW_ADD_MANAGED_PROFILE}.
      * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      *
      * @see #createProfileForUser(String, int, int, String[])
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java
index 1447e7d..466a7e3 100644
--- a/core/java/android/os/UserManagerInternal.java
+++ b/core/java/android/os/UserManagerInternal.java
@@ -120,7 +120,8 @@
     public abstract void onEphemeralUserStop(int userId);
 
     /**
-     * Same as UserManager.createUser(), but bypasses the check for DISALLOW_ADD_USER.
+     * Same as UserManager.createUser(), but bypasses the check for
+     * {@link UserManager#DISALLOW_ADD_USER} and {@link UserManager#DISALLOW_ADD_MANAGED_PROFILE}
      *
      * <p>Called by the {@link com.android.server.devicepolicy.DevicePolicyManagerService} when
      * createAndManageUser is called by the device owner.
@@ -129,7 +130,8 @@
 
     /**
      * Same as {@link UserManager#removeUser(int userHandle)}, but bypasses the check for
-     * {@link UserManager#DISALLOW_REMOVE_USER} and does not require the
+     * {@link UserManager#DISALLOW_REMOVE_USER} and
+     * {@link UserManager#DISALLOW_REMOVE_MANAGED_PROFILE} and does not require the
      * {@link android.Manifest.permission#MANAGE_USERS} permission.
      */
     public abstract boolean removeUserEvenWhenDisallowed(int userId);
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index c45fe5a..5ac33a1 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -170,6 +170,10 @@
      * make easily identifyable processes even if you are using the same base
      * <var>processClass</var> to start them.
      *
+     * When invokeWith is not null, the process will be started as a fresh app
+     * and not a zygote fork. Note that this is only allowed for uid 0 or when
+     * debugFlags contains DEBUG_ENABLE_DEBUGGER.
+     *
      * @param processClass The class to use as the process's main entry
      *                     point.
      * @param niceName A more readable name to use for the process.
@@ -182,6 +186,7 @@
      * @param abi non-null the ABI this app should be started with.
      * @param instructionSet null-ok the instruction set to use.
      * @param appDataDir null-ok the data directory of the app.
+     * @param invokeWith null-ok the command to invoke with.
      * @param zygoteArgs Additional arguments to supply to the zygote process.
      *
      * @return An object that describes the result of the attempt to start the process.
@@ -196,11 +201,12 @@
                                                   String abi,
                                                   String instructionSet,
                                                   String appDataDir,
+                                                  String invokeWith,
                                                   String[] zygoteArgs) {
         try {
             return startViaZygote(processClass, niceName, uid, gid, gids,
                     debugFlags, mountExternal, targetSdkVersion, seInfo,
-                    abi, instructionSet, appDataDir, zygoteArgs);
+                    abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
         } catch (ZygoteStartFailedEx ex) {
             Log.e(LOG_TAG,
                     "Starting VM process through Zygote failed");
@@ -330,6 +336,7 @@
                                                       String abi,
                                                       String instructionSet,
                                                       String appDataDir,
+                                                      String invokeWith,
                                                       String[] extraArgs)
                                                       throws ZygoteStartFailedEx {
         ArrayList<String> argsForZygote = new ArrayList<String>();
@@ -407,6 +414,11 @@
             argsForZygote.add("--app-data-dir=" + appDataDir);
         }
 
+        if (invokeWith != null) {
+            argsForZygote.add("--invoke-with");
+            argsForZygote.add(invokeWith);
+        }
+
         argsForZygote.add(processClass);
 
         if (extraArgs != null) {
diff --git a/core/java/android/service/autofill/AutoFillService.java b/core/java/android/service/autofill/AutoFillService.java
index 5f27e34..a7941c7 100644
--- a/core/java/android/service/autofill/AutoFillService.java
+++ b/core/java/android/service/autofill/AutoFillService.java
@@ -15,6 +15,11 @@
  */
 package android.service.autofill;
 
+import static android.service.voice.VoiceInteractionSession.KEY_FLAGS;
+import static android.service.voice.VoiceInteractionSession.KEY_STRUCTURE;
+import static android.view.View.ASSIST_FLAG_SANITIZED_TEXT;
+import static android.view.View.ASSIST_FLAG_NON_SANITIZED_TEXT;
+
 import android.annotation.SdkConstant;
 import android.app.Activity;
 import android.app.Service;
@@ -26,13 +31,14 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
-import android.service.voice.VoiceInteractionSession;
 import android.util.Log;
 
 import com.android.internal.os.HandlerCaller;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.os.SomeArgs;
 
+// TODO(b/33197203): improve javadoc (class and methods)
+
 /**
  * Top-level service of the current auto-fill service for a given user.
  *
@@ -52,6 +58,11 @@
     @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
     public static final String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
 
+    // Bundle keys.
+    /** @hide */
+    public static final String KEY_CALLBACK = "callback";
+
+    // Handler messages.
     private static final int MSG_CONNECT = 1;
     private static final int MSG_AUTO_FILL_ACTIVITY = 2;
     private static final int MSG_DISCONNECT = 3;
@@ -59,14 +70,12 @@
     private final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
         @Override
         public void send(int resultCode, Bundle resultData) throws RemoteException {
-            final AssistStructure structure = resultData
-                    .getParcelable(VoiceInteractionSession.KEY_STRUCTURE);
-
-            final IBinder binder = resultData
-                    .getBinder(VoiceInteractionSession.KEY_AUTO_FILL_CALLBACK);
+            final AssistStructure structure = resultData.getParcelable(KEY_STRUCTURE);
+            final IBinder binder = resultData.getBinder(KEY_CALLBACK);
+            final int flags = resultData.getInt(KEY_FLAGS, 0);
 
             mHandlerCaller
-                .obtainMessageOO(MSG_AUTO_FILL_ACTIVITY, structure, binder).sendToTarget();
+                .obtainMessageIOO(MSG_AUTO_FILL_ACTIVITY, flags, structure, binder).sendToTarget();
         }
 
     };
@@ -100,7 +109,8 @@
                     final SomeArgs args = (SomeArgs) msg.obj;
                     final AssistStructure structure = (AssistStructure) args.arg1;
                     final IBinder binder = (IBinder) args.arg2;
-                    requestAutoFill(structure, binder);
+                    final int flags = msg.arg1;
+                    requestAutoFill(structure, flags, binder);
                     break;
                 } case MSG_DISCONNECT: {
                     onDisconnected();
@@ -145,19 +155,46 @@
     }
 
     /**
-     * Handles an auto-fill request.
+     * Called when user requests service to auto-fill an {@link Activity}.
      *
      * @param structure {@link Activity}'s view structure .
+     * @param data bundle with optional parameters (currently none) which is passed along on
+     * subsequent calls (so it can be used by the service to share data).
      * @param cancellationSignal signal for observing cancel requests.
-     * @param callback object used to fulllfill the request.
      */
     public abstract void onFillRequest(AssistStructure structure,
-            CancellationSignal cancellationSignal, FillCallback callback);
+            Bundle data, CancellationSignal cancellationSignal, FillCallback callback);
 
-    private void requestAutoFill(AssistStructure structure, IBinder binder) {
-        final FillCallback callback = new FillCallback(binder);
-        // TODO: hook up the cancelationSignal
-        onFillRequest(structure, new CancellationSignal(), callback);
+    /**
+     * Called when user requests service to save the fields of an {@link Activity}.
+     *
+     * @param structure {@link Activity}'s view structure.
+     * @param data same bundle passed to
+     * {@link #onFillRequest(AssistStructure, Bundle, CancellationSignal, FillCallback)};
+     * might also contain with optional parameters (currently none).
+     * @param cancellationSignal signal for observing cancel requests.
+     * @param callback object used to notify the result of the request.
+     */
+    public abstract void onSaveRequest(AssistStructure structure,
+            Bundle data, CancellationSignal cancellationSignal, SaveCallback callback);
+
+    private void requestAutoFill(AssistStructure structure, int flags, IBinder binder) {
+        // TODO(b/33197203): pass the Bundle received from mAssistReceiver instead?
+        final Bundle data = new Bundle();
+        switch (flags) {
+            case ASSIST_FLAG_SANITIZED_TEXT:
+                final FillCallback fillCallback = new FillCallback(binder);
+                // TODO(b/33197203): hook up the cancelationSignal
+                onFillRequest(structure, data, new CancellationSignal(), fillCallback);
+                break;
+            case ASSIST_FLAG_NON_SANITIZED_TEXT:
+                final SaveCallback saveCallback = new SaveCallback(binder);
+                // TODO(b/33197203): hook up the cancelationSignal
+                onSaveRequest(structure, null, new CancellationSignal(), saveCallback);
+                break;
+            default:
+                Log.w(TAG, "invalid flag on requestAutoFill(): " + flags);
+        }
     }
 
     /**
diff --git a/core/java/android/service/autofill/FillCallback.java b/core/java/android/service/autofill/FillCallback.java
index 2308440..3284b90 100644
--- a/core/java/android/service/autofill/FillCallback.java
+++ b/core/java/android/service/autofill/FillCallback.java
@@ -17,7 +17,6 @@
 package android.service.autofill;
 
 import static android.service.autofill.AutoFillService.DEBUG;
-import static android.service.autofill.AutoFillService.TAG;
 
 import android.app.Activity;
 import android.app.assist.AssistStructure.ViewNode;
@@ -38,6 +37,8 @@
  */
 public final class FillCallback {
 
+    private static final String TAG = "FillCallback";
+
     private final IAutoFillCallback mCallback;
 
     /** @hide */
@@ -62,6 +63,13 @@
         }
     }
 
+    /**
+     * Notifies the {@link Activity} that the auto-fill request failed.
+     *
+     * @param message error message to be displayed.
+     *
+     * @throws RuntimeException if an error occurred while notifying the activity.
+     */
     public void onFailure(CharSequence message) {
         if (DEBUG) Log.d(TAG, "onFailure(): message=" + message);
 
diff --git a/core/java/android/service/autofill/IAutoFillManagerService.aidl b/core/java/android/service/autofill/IAutoFillManagerService.aidl
index 76a2561..f1251c0 100644
--- a/core/java/android/service/autofill/IAutoFillManagerService.aidl
+++ b/core/java/android/service/autofill/IAutoFillManagerService.aidl
@@ -25,11 +25,5 @@
  */
 oneway interface IAutoFillManagerService {
 
-    /**
-     * Request auto-fill on the top activity of a given user.
-     *
-     * @param userId user handle.
-     * @param activityToken optional token of activity that needs to be on top.
-     */
-    void requestAutoFill(int userId, IBinder activityToken);
+    void requestAutoFill(IBinder activityToken, int userId, int flags);
 }
diff --git a/core/java/android/service/autofill/SaveCallback.java b/core/java/android/service/autofill/SaveCallback.java
new file mode 100644
index 0000000..4dc7392
--- /dev/null
+++ b/core/java/android/service/autofill/SaveCallback.java
@@ -0,0 +1,79 @@
+/*
+ * 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.service.autofill;
+
+import static android.service.autofill.AutoFillService.DEBUG;
+
+import android.app.Activity;
+import android.app.assist.AssistStructure.ViewNode;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Handles save requests from the {@link AutoFillService} into the {@link Activity} being
+ * auto-filled.
+ */
+public final class SaveCallback {
+
+    private static final String TAG = "SaveCallback";
+
+    private final IAutoFillCallback mCallback;
+
+    /** @hide */
+    SaveCallback(IBinder binder) {
+        mCallback = IAutoFillCallback.Stub.asInterface(binder);
+    }
+
+    /**
+     * Notifies the {@link Activity} that the save request succeeded.
+     *
+     * @param ids ids ({@link ViewNode#getAutoFillId()}) of the fields that were saved.
+     *
+     * @throws RuntimeException if an error occurred while saving the data.
+     */
+    public void onSuccess(int[] ids) {
+        Preconditions.checkArgument(ids != null, "ids cannot be null");
+
+        Preconditions.checkArgument(ids.length > 0, "ids cannot be empty");
+
+        if (DEBUG) Log.d(TAG, "onSuccess(): ids=" + ids.length);
+
+        // TODO(b/33197203): display which ids were saved
+    }
+
+    /**
+     * Notifies the {@link Activity} that the save request failed.
+     *
+     * @param message error message to be displayed.
+     *
+     * @throws RuntimeException if an error occurred while notifying the activity.
+     */
+    public void onFailure(CharSequence message) {
+        if (DEBUG) Log.d(TAG, "onFailure(): message=" + message);
+
+        Preconditions.checkArgument(message != null, "message cannot be null");
+
+        try {
+            mCallback.showError(message.toString());
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
+        }
+    }
+}
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index 4e00c64..51ba8c72 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -16,7 +16,10 @@
 
 package android.service.notification;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SdkConstant;
+import android.app.NotificationChannel;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Handler;
@@ -27,6 +30,7 @@
 import android.util.Log;
 import com.android.internal.os.SomeArgs;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -79,9 +83,10 @@
     public final void adjustNotification(Adjustment adjustment) {
         if (!isBound()) return;
         try {
-            getNotificationInterface().applyAdjustmentFromAssistantService(mWrapper, adjustment);
+            getNotificationInterface().applyAdjustmentFromAssistant(mWrapper, adjustment);
         } catch (android.os.RemoteException ex) {
             Log.v(TAG, "Unable to contact notification manager", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -95,12 +100,77 @@
     public final void adjustNotifications(List<Adjustment> adjustments) {
         if (!isBound()) return;
         try {
-            getNotificationInterface().applyAdjustmentsFromAssistantService(mWrapper, adjustments);
+            getNotificationInterface().applyAdjustmentsFromAssistant(mWrapper, adjustments);
         } catch (android.os.RemoteException ex) {
             Log.v(TAG, "Unable to contact notification manager", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
+    /**
+     * Creates a notification channel that notifications can be posted to for a given package.
+     *
+     * @param pkg The package to create a channel for.
+     * @param channel  the channel to attempt to create.
+     */
+    public void createNotificationChannel(@NonNull String pkg,
+            @NonNull NotificationChannel channel) {
+        if (!isBound()) return;
+        try {
+            getNotificationInterface().createNotificationChannelFromAssistant(
+                    mWrapper, pkg, channel);
+        } catch (RemoteException e) {
+            Log.v(TAG, "Unable to contact notification manager", e);
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Updates a notification channel for a given package.
+     *
+     * @param pkg The package to the channel belongs to.
+     * @param channel the channel to attempt to update.
+     */
+    public void updateNotificationChannel(@NonNull String pkg,
+            @NonNull NotificationChannel channel) {
+        if (!isBound()) return;
+        try {
+            getNotificationInterface().updateNotificationChannelFromAssistant(
+                    mWrapper, pkg, channel);
+        } catch (RemoteException e) {
+            Log.v(TAG, "Unable to contact notification manager", e);
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns all notification channels belonging to the given package.
+     */
+    public List<NotificationChannel> getNotificationChannels(@NonNull String pkg) {
+        if (!isBound()) return null;
+        try {
+            return getNotificationInterface().getNotificationChannelsFromAssistant(
+                    mWrapper, pkg).getList();
+        } catch (RemoteException e) {
+            Log.v(TAG, "Unable to contact notification manager", e);
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Deletes the given notification channel.
+     */
+    public void deleteNotificationChannel(@NonNull String pkg, @NonNull String channelId) {
+        if (!isBound()) return;
+        try {
+            getNotificationInterface().deleteNotificationChannelFromAssistant(
+                    mWrapper, pkg, channelId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+
     private class NotificationAssistantServiceWrapper extends NotificationListenerWrapper {
         @Override
         public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder,
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 12aed25..48f3ac3 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -120,7 +120,7 @@
     /** @hide */
     public static final String KEY_RECEIVER_EXTRAS = "receiverExtras";
     /** @hide */
-    public static final String KEY_AUTO_FILL_CALLBACK = "autoFillCallback";
+    public static final String KEY_FLAGS = "flags";
 
     final Context mContext;
     final HandlerCaller mHandlerCaller;
diff --git a/core/java/android/text/AndroidCharacter.java b/core/java/android/text/AndroidCharacter.java
index b150b6e..c5f1a01 100644
--- a/core/java/android/text/AndroidCharacter.java
+++ b/core/java/android/text/AndroidCharacter.java
@@ -17,9 +17,11 @@
 package android.text;
 
 /**
- * AndroidCharacter exposes some character properties that are not
- * easily accessed from java.lang.Character.
+ * AndroidCharacter exposes some character properties that used to be not
+ * easily accessed from java.lang.Character, but are now available in ICU.
+ * @deprecated Use various methods from {@link android.icu.lang.UCharacter}, instead.
  */
+@Deprecated
 public class AndroidCharacter
 {
     public static final int EAST_ASIAN_WIDTH_NEUTRAL = 0;
diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java
index de8aa5a..c3aac74 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -40,8 +40,6 @@
 import android.text.style.URLSpan;
 import android.text.style.UnderlineSpan;
 
-import com.android.internal.util.ArrayUtils;
-
 import org.ccil.cowan.tagsoup.HTMLSchema;
 import org.ccil.cowan.tagsoup.Parser;
 import org.xml.sax.Attributes;
@@ -342,19 +340,10 @@
     }
 
     private static String getTextDirection(Spanned text, int start, int end) {
-        final int len = end - start;
-        final byte[] levels = ArrayUtils.newUnpaddedByteArray(len);
-        final char[] buffer = TextUtils.obtain(len);
-        TextUtils.getChars(text, start, end, buffer, 0);
-
-        int paraDir = AndroidBidi.bidi(Layout.DIR_REQUEST_DEFAULT_LTR, buffer, levels, len,
-                false /* no info */);
-        switch(paraDir) {
-            case Layout.DIR_RIGHT_TO_LEFT:
-                return " dir=\"rtl\"";
-            case Layout.DIR_LEFT_TO_RIGHT:
-            default:
-                return " dir=\"ltr\"";
+        if (TextDirectionHeuristics.FIRSTSTRONG_LTR.isRtl(text, start, end - start)) {
+            return " dir=\"rtl\"";
+        } else {
+            return " dir=\"ltr\"";
         }
     }
 
diff --git a/core/java/android/text/TextClassificationManager.java b/core/java/android/text/TextClassificationManager.java
new file mode 100644
index 0000000..d4548f0
--- /dev/null
+++ b/core/java/android/text/TextClassificationManager.java
@@ -0,0 +1,62 @@
+/*
+ * 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.annotation.NonNull;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Interface to the text classification service.
+ * This class uses machine learning techniques to infer things about text.
+ * Unless otherwise stated, methods of this class are blocking operations and should most likely not
+ * be called on the UI thread.
+ *
+ * <p> You do not instantiate this class directly; instead, retrieve it through
+ * {@link android.content.Context#getSystemService}.
+ *
+ * The TextClassificationManager serves as the default TextAssistant if none has been set.
+ * @see android.app.Activity#setTextAssistant(TextAssistant).
+ */
+public final class TextClassificationManager implements TextAssistant {
+    // TODO: Consider not making this class implement TextAssistant.
+
+    /** @hide */
+    public TextClassificationManager() {}
+
+    /**
+     * Returns information containing languages that were detected in the provided text.
+     * This is a blocking operation and should most likely not be called on the UI thread.
+     */
+    public List<TextLanguage> detectLanguages(@NonNull CharSequence text) {
+        // TODO: Implement this using the cld3 library.
+        return Collections.emptyList();
+    }
+
+    @Override
+    public TextSelection suggestSelection(
+            @NonNull CharSequence text, int selectionStartIndex, int selectionEndIndex) {
+        // TODO: Implement.
+        return TextAssistant.NO_OP.suggestSelection(text, selectionStartIndex, selectionEndIndex);
+    }
+
+    @Override
+    public void addLinks(@NonNull Spannable text, int linkMask) {
+        // TODO: Implement.
+    }
+}
diff --git a/core/java/android/text/TextLanguage.java b/core/java/android/text/TextLanguage.java
new file mode 100644
index 0000000..eb834f1
--- /dev/null
+++ b/core/java/android/text/TextLanguage.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 android.text;
+
+import android.annotation.NonNull;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Specifies detected languages for a section of text indicated by a start and end index.
+ */
+public final class TextLanguage {
+
+    private final int mStartIndex;
+    private final int mEndIndex;
+    private final Map<String, Float> mLanguageConfidence;
+
+    /**
+     * Initializes a TextLanguage object.
+     *
+     * @param startIndex the start index of the detected languages in the text provided to generate
+     *      this object.
+     * @param endIndex the end index of the detected languages in the text provided to generate this
+     *      object.
+     * @param languageConfidence a map of detected language to confidence score. The language string
+     *      is a BCP-47 language tag.
+     * @throws NullPointerException if languageConfidence is null or contains a null key or value.
+     */
+    public TextLanguage(int startIndex, int endIndex,
+            @NonNull Map<String, Float> languageConfidence) {
+        mStartIndex = startIndex;
+        mEndIndex = endIndex;
+
+        Map<String, Float> map = new LinkedHashMap<>();
+        Preconditions.checkNotNull(languageConfidence).entrySet().stream()
+                .sorted(Map.Entry.comparingByValue())
+                .forEach(entry -> map.put(
+                        Preconditions.checkNotNull(entry.getKey()),
+                        Preconditions.checkNotNull(entry.getValue())));
+        mLanguageConfidence = Collections.unmodifiableMap(map);
+    }
+
+    /**
+     * Returns the start index of the detected languages in the text provided to generate this
+     * object.
+     */
+    public int getStartIndex() {
+        return mStartIndex;
+    }
+
+    /**
+     * Returns the end index of the detected languages in the text provided to generate this object.
+     */
+    public int getEndIndex() {
+        return mEndIndex;
+    }
+
+    /**
+     * Returns an unmodifiable map of detected language to confidence score. The map entries are
+     * ordered from high confidence score (1) to low confidence score (0). The language string is a
+     * BCP-47 language tag.
+     */
+    @NonNull
+    public Map<String, Float> getLanguageConfidence() {
+        return mLanguageConfidence;
+    }
+}
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 6262fc2..58bc9a7 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -22,6 +22,7 @@
 import android.annotation.PluralsRes;
 import android.content.Context;
 import android.content.res.Resources;
+import android.icu.lang.UCharacter;
 import android.icu.util.ULocale;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -545,9 +546,10 @@
         }
 
         public char charAt(int off) {
-            return AndroidCharacter.getMirror(mSource.charAt(mEnd - 1 - off));
+            return (char) UCharacter.getMirror(mSource.charAt(mEnd - 1 - off));
         }
 
+        @SuppressWarnings("deprecation")
         public void getChars(int start, int end, char[] dest, int destoff) {
             TextUtils.getChars(mSource, start + mStart, end + mStart,
                                dest, destoff);
diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java
index f16e714..e19b2c7 100644
--- a/core/java/android/text/format/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -19,6 +19,10 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.icu.text.MeasureFormat;
+import android.icu.text.MeasureFormat.FormatWidth;
+import android.icu.util.Measure;
+import android.icu.util.MeasureUnit;
 
 import com.android.internal.R;
 
@@ -351,26 +355,54 @@
     }
 
     /**
-     * Return given duration in a human-friendly format. For example, "4
-     * minutes" or "1 second". Returns only largest meaningful unit of time,
+     * Returns the given duration in a human-friendly format. For example,
+     * "4 minutes" or "1 second". Returns only the largest meaningful unit of time,
      * from seconds up to hours.
      *
      * @hide
      */
     public static CharSequence formatDuration(long millis) {
-        final Resources res = Resources.getSystem();
+        return formatDuration(millis, LENGTH_LONG);
+    }
+
+    /**
+     * Returns the given duration in a human-friendly format. For example,
+     * "4 minutes" or "1 second". Returns only the largest meaningful unit of time,
+     * from seconds up to hours.
+     * <p>
+     * You can use abbrev to specify a preference for abbreviations (but note that some
+     * locales may not have abbreviations). Use LENGTH_LONG for the full spelling (e.g. "2 hours"),
+     * LENGTH_SHORT for the abbreviated spelling if available (e.g. "2 hr"), and LENGTH_SHORTEST for
+     * the briefest form available (e.g. "2h").
+     * @hide
+     */
+    public static CharSequence formatDuration(long millis, int abbrev) {
+        final FormatWidth width;
+        switch (abbrev) {
+            case LENGTH_LONG:
+                width = FormatWidth.WIDE;
+                break;
+            case LENGTH_SHORT:
+            case LENGTH_SHORTER:
+            case LENGTH_MEDIUM:
+                width = FormatWidth.SHORT;
+                break;
+            case LENGTH_SHORTEST:
+                width = FormatWidth.NARROW;
+                break;
+            default:
+                width = FormatWidth.WIDE;
+        }
+        final MeasureFormat formatter = MeasureFormat.getInstance(Locale.getDefault(), width);
         if (millis >= HOUR_IN_MILLIS) {
             final int hours = (int) ((millis + 1800000) / HOUR_IN_MILLIS);
-            return res.getQuantityString(
-                    com.android.internal.R.plurals.duration_hours, hours, hours);
+            return formatter.format(new Measure(hours, MeasureUnit.HOUR));
         } else if (millis >= MINUTE_IN_MILLIS) {
             final int minutes = (int) ((millis + 30000) / MINUTE_IN_MILLIS);
-            return res.getQuantityString(
-                    com.android.internal.R.plurals.duration_minutes, minutes, minutes);
+            return formatter.format(new Measure(minutes, MeasureUnit.MINUTE));
         } else {
             final int seconds = (int) ((millis + 500) / SECOND_IN_MILLIS);
-            return res.getQuantityString(
-                    com.android.internal.R.plurals.duration_seconds, seconds, seconds);
+            return formatter.format(new Measure(seconds, MeasureUnit.SECOND));
         }
     }
 
diff --git a/core/java/android/text/style/RasterizerSpan.java b/core/java/android/text/style/RasterizerSpan.java
index cae9640..f0be50a 100644
--- a/core/java/android/text/style/RasterizerSpan.java
+++ b/core/java/android/text/style/RasterizerSpan.java
@@ -19,6 +19,9 @@
 import android.graphics.Rasterizer;
 import android.text.TextPaint;
 
+/**
+ *  @removed Rasterizer is not supported for hw-accerlerated and PDF rendering
+ */
 public class RasterizerSpan extends CharacterStyle implements UpdateAppearance {
 
     private Rasterizer mRasterizer;
diff --git a/core/java/android/view/DisplayListCanvas.java b/core/java/android/view/DisplayListCanvas.java
index 106f172..8f9ae0e 100644
--- a/core/java/android/view/DisplayListCanvas.java
+++ b/core/java/android/view/DisplayListCanvas.java
@@ -23,6 +23,7 @@
 import android.graphics.Paint;
 import android.util.Pools.SynchronizedPool;
 
+import dalvik.annotation.optimization.CriticalNative;
 import dalvik.annotation.optimization.FastNative;
 
 /**
@@ -230,30 +231,37 @@
         }
     }
 
-    @FastNative
-    private static native long nCreateDisplayListCanvas(long node, int width, int height);
-    @FastNative
-    private static native void nResetDisplayListCanvas(long canvas, long node,
-            int width, int height);
-    @FastNative
-    private static native int nGetMaximumTextureWidth();
-    @FastNative
-    private static native int nGetMaximumTextureHeight();
-    @FastNative
-    private static native void nInsertReorderBarrier(long renderer, boolean enableReorder);
+
+    // ------------------ Fast JNI ------------------------
+
     @FastNative
     private static native void nCallDrawGLFunction(long renderer,
             long drawGLFunction, Runnable releasedCallback);
-    @FastNative
+
+
+    // ------------------ Critical JNI ------------------------
+
+    @CriticalNative
+    private static native long nCreateDisplayListCanvas(long node, int width, int height);
+    @CriticalNative
+    private static native void nResetDisplayListCanvas(long canvas, long node,
+            int width, int height);
+    @CriticalNative
+    private static native int nGetMaximumTextureWidth();
+    @CriticalNative
+    private static native int nGetMaximumTextureHeight();
+    @CriticalNative
+    private static native void nInsertReorderBarrier(long renderer, boolean enableReorder);
+    @CriticalNative
     private static native long nFinishRecording(long renderer);
-    @FastNative
+    @CriticalNative
     private static native void nDrawRenderNode(long renderer, long renderNode);
-    @FastNative
+    @CriticalNative
     private static native void nDrawLayer(long renderer, long layer);
-    @FastNative
+    @CriticalNative
     private static native void nDrawCircle(long renderer, long propCx,
             long propCy, long propRadius, long propPaint);
-    @FastNative
+    @CriticalNative
     private static native void nDrawRoundRect(long renderer, long propLeft, long propTop,
             long propRight, long propBottom, long propRx, long propRy, long propPaint);
 }
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index d563f51..3f3d519 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.graphics.Rect;
 import android.util.ArrayMap;
 import android.util.SparseArray;
@@ -24,6 +26,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.List;
 
 /**
  * The algorithm used for finding the next focusable view in a given direction
@@ -102,6 +105,30 @@
         return next;
     }
 
+    /**
+     * Find the root of the next keyboard navigation cluster after the current one.
+     * @param root Thew view tree to look inside. Cannot be null
+     * @param currentCluster The starting point of the search. Null means the default cluster
+     * @param direction Direction to look
+     * @return The next cluster, or null if none exists
+     */
+    public View findNextKeyboardNavigationCluster(
+            @NonNull ViewGroup root, @Nullable View currentCluster, int direction) {
+        View next = null;
+
+        final ArrayList<View> clusters = mTempList;
+        try {
+            clusters.clear();
+            root.addKeyboardNavigationClusters(clusters, direction);
+            if (!clusters.isEmpty()) {
+                next = findNextKeyboardNavigationCluster(root, currentCluster, clusters, direction);
+            }
+        } finally {
+            clusters.clear();
+        }
+        return next;
+    }
+
     private View findNextUserSpecifiedFocus(ViewGroup root, View focused, int direction) {
         // check for user specified next focus
         View userSetNextFocus = focused.findUserSetNextFocus(root, direction);
@@ -170,6 +197,24 @@
         }
     }
 
+    private View findNextKeyboardNavigationCluster(ViewGroup root, View currentCluster,
+            List<View> clusters, int direction) {
+        final int count = clusters.size();
+
+        switch (direction) {
+            case View.FOCUS_FORWARD:
+            case View.FOCUS_DOWN:
+            case View.FOCUS_RIGHT:
+                return getNextKeyboardNavigationCluster(root, currentCluster, clusters, count);
+            case View.FOCUS_BACKWARD:
+            case View.FOCUS_UP:
+            case View.FOCUS_LEFT:
+                return getPreviousKeyboardNavigationCluster(root, currentCluster, clusters, count);
+            default:
+                throw new IllegalArgumentException("Unknown direction: " + direction);
+        }
+    }
+
     private View findNextFocusInRelativeDirection(ArrayList<View> focusables, ViewGroup root,
             View focused, Rect focusedRect, int direction) {
         try {
@@ -270,6 +315,45 @@
         return null;
     }
 
+    private static View getNextKeyboardNavigationCluster(ViewGroup root, View currentCluster,
+            List<View> clusters, int count) {
+        if (currentCluster == null) {
+            // The current cluster is the default one.
+            // The next cluster after the default one is the first one.
+            // Note that the caller guarantees that 'clusters' is not empty.
+            return clusters.get(0);
+        }
+
+        final int position = clusters.lastIndexOf(currentCluster);
+        if (position >= 0 && position + 1 < count) {
+            // Return the next non-default cluster if we can find it.
+            return clusters.get(position + 1);
+        }
+
+        // The current cluster is the last one. The next one is the default one, i.e. the root.
+        return root;
+    }
+
+    private static View getPreviousKeyboardNavigationCluster(ViewGroup root, View currentCluster,
+            List<View> clusters, int count) {
+        if (currentCluster == null) {
+            // The current cluster is the default one.
+            // The previous cluster before the default one is the last one.
+            // Note that the caller guarantees that 'clusters' is not empty.
+            return clusters.get(count - 1);
+        }
+
+        final int position = clusters.indexOf(currentCluster);
+        if (position > 0) {
+            // Return the previous non-default cluster if we can find it.
+            return clusters.get(position - 1);
+        }
+
+        // The current cluster is the first one. The previous one is the default one, i.e. the
+        // root.
+        return root;
+    }
+
     /**
      * Is rect1 a better candidate than rect2 for a focus search in a particular
      * direction from a source rect?  This is the core routine that determines
diff --git a/core/java/android/view/IPinnedStackListener.aidl b/core/java/android/view/IPinnedStackListener.aidl
index 3050dbb..3c348c5 100644
--- a/core/java/android/view/IPinnedStackListener.aidl
+++ b/core/java/android/view/IPinnedStackListener.aidl
@@ -16,13 +16,14 @@
 
 package android.view;
 
+import android.content.pm.ParceledListSlice;
 import android.view.IPinnedStackController;
 
 /**
-  * Listener for changes to the pinned stack made by the WindowManager.
-  *
-  * @hide
-  */
+ * Listener for changes to the pinned stack made by the WindowManager.
+ *
+ * @hide
+ */
 oneway interface IPinnedStackListener {
 
     /**
@@ -36,4 +37,24 @@
      * is first registered to allow the listener to synchronized its state with the controller.
      */
     void onBoundsChanged(boolean adjustedForIme);
+
+    /**
+     * Called when window manager decides to adjust the minimized state, or when the listener
+     * is first registered to allow the listener to synchronized its state with the controller.
+     */
+    void onMinimizedStateChanged(boolean isMinimized);
+
+    /**
+     * Called when window manager decides to adjust the snap-to-edge state, which determines whether
+     * to snap only to the corners of the screen or to the closest edge.  It is called when the
+     * listener is first registered to allow the listener to synchronized its state with the
+     * controller.
+     */
+    void onSnapToEdgeStateChanged(boolean isSnapToEdge);
+
+    /**
+     * Called when the set of actions for the current PiP activity changes, or when the listener
+     * is first registered to allow the listener to synchronized its state with the controller.
+     */
+    void onActionsChanged(in ParceledListSlice actions);
 }
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index bd1ad8e..21875fe 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -89,51 +89,33 @@
     void addWindowToken(IBinder token, int type, int displayId);
     void removeWindowToken(IBinder token, int displayId);
     /**
-     * Adds an application token to the specified task Id.
+     * Creates the object representation for the application token in the window manager and adds it
+     * to the specified task Id.
+     *
      * @param addPos The position to add the token to in the task.
      * @param token The token to add.
      * @param taskId The Id of the task we are adding the token to.
-     * @param stackId Stack Id to create a new Task with the input task Id on
-     *                if the task doesn't exist yet.
      * @param requestedOrientation Orientation to use.
      * @param fullscreen True if the application token is fullscreen.
      * @param showWhenLocked True if the application token should be shown when locked.
-     * @param userId Id of user to associate the token with.
      * @param configChanges Input configuration changes.
      * @param voiceInteraction True if the token is in voice interaction mode.
      * @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 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.
-     * @param homeTask True if this is the task.
      * @param targetSdkVersion The application's target SDK version
-     * @param isOnTopLauncher True if this task is an on-top launcher.
      */
-    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 overrideConfig, int taskResizeMode,
-            boolean alwaysFocusable, boolean homeTask, int targetSdkVersion,
-            int rotationAnimationHint, boolean isOnTopLauncher);
+    void addAppToken(int addPos, IApplicationToken token, int taskId, int requestedOrientation,
+            boolean fullscreen, boolean showWhenLocked, int configChanges, boolean voiceInteraction,
+            boolean launchTaskBehind, boolean alwaysFocusable, int targetSdkVersion,
+            int rotationAnimationHint);
     /**
+     * Adds an already existing application token on the window manager side to the input task id.
      *
      * @param token The token we are adding to the input task Id.
      * @param taskId The Id of the task we are adding the token to.
-     * @param stackId Stack Id to create a new Task with the input task Id on
-     *                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 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 overrideConfig, int taskResizeMode, boolean homeTask,
-            boolean isOnTopLauncher);
+    void addAppToTask(IBinder token, int taskId);
     void setAppOrientation(IApplicationToken token, int requestedOrientation);
     int getAppOrientation(IApplicationToken token);
     void setFocusedApp(IBinder token, boolean moveFocusNow);
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 8eca431..fc66697 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -24,6 +24,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.AnimatedVectorDrawable;
 
+import dalvik.annotation.optimization.CriticalNative;
 import dalvik.annotation.optimization.FastNative;
 
 import libcore.util.NativeAllocationRegistry;
@@ -138,7 +139,9 @@
                 RenderNode.class.getClassLoader(), nGetNativeFinalizer(), 1024);
     }
 
+    // Note: written by native when display lists are detached
     private boolean mValid;
+
     // Do not access directly unless you are ThreadedRenderer
     final long mNativeRenderNode;
     private final View mOwningView;
@@ -792,13 +795,6 @@
         return nGetDebugSize(mNativeRenderNode);
     }
 
-    /**
-     * Called by native when the passed displaylist is removed from the draw tree
-     */
-    void onRenderNodeDetached() {
-        discardDisplayList();
-    }
-
     ///////////////////////////////////////////////////////////////////////////
     // Animations
     ///////////////////////////////////////////////////////////////////////////
@@ -828,14 +824,13 @@
     }
 
     ///////////////////////////////////////////////////////////////////////////
-    // Native methods
+    // Regular JNI methods
     ///////////////////////////////////////////////////////////////////////////
 
     // Intentionally not static because it acquires a reference to 'this'
     private native long nCreate(String name);
 
     private static native long nGetNativeFinalizer();
-    private static native void nSetDisplayList(long renderNode, long newData);
     private static native void nOutput(long renderNode);
     private static native int nGetDebugSize(long renderNode);
     private static native void nRequestPositionUpdates(long renderNode, SurfaceView callback);
@@ -845,132 +840,141 @@
     private static native void nAddAnimator(long renderNode, long animatorPtr);
     private static native void nEndAllAnimators(long renderNode);
 
+
     ///////////////////////////////////////////////////////////////////////////
-    // Fast native methods
+    // @FastNative methods
+    ///////////////////////////////////////////////////////////////////////////
+
+    @FastNative
+    private static native void nSetDisplayList(long renderNode, long newData);
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // @CriticalNative methods
     ///////////////////////////////////////////////////////////////////////////
 
     // Matrix
 
-    @FastNative
+    @CriticalNative
     private static native void nGetTransformMatrix(long renderNode, long nativeMatrix);
-    @FastNative
+    @CriticalNative
     private static native void nGetInverseTransformMatrix(long renderNode, long nativeMatrix);
-    @FastNative
+    @CriticalNative
     private static native boolean nHasIdentityMatrix(long renderNode);
 
     // Properties
 
-    @FastNative
+    @CriticalNative
     private static native boolean nOffsetTopAndBottom(long renderNode, int offset);
-    @FastNative
+    @CriticalNative
     private static native boolean nOffsetLeftAndRight(long renderNode, int offset);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetLeftTopRightBottom(long renderNode, int left, int top,
             int right, int bottom);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetBottom(long renderNode, int bottom);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetRight(long renderNode, int right);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetTop(long renderNode, int top);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetLeft(long renderNode, int left);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetCameraDistance(long renderNode, float distance);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetPivotY(long renderNode, float pivotY);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetPivotX(long renderNode, float pivotX);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetLayerType(long renderNode, int layerType);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetLayerPaint(long renderNode, long paint);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetClipToBounds(long renderNode, boolean clipToBounds);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetClipBounds(long renderNode, int left, int top,
             int right, int bottom);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetClipBoundsEmpty(long renderNode);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetProjectBackwards(long renderNode, boolean shouldProject);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetProjectionReceiver(long renderNode, boolean shouldRecieve);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetOutlineRoundRect(long renderNode, int left, int top,
             int right, int bottom, float radius, float alpha);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetOutlineConvexPath(long renderNode, long nativePath,
             float alpha);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetOutlineEmpty(long renderNode);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetOutlineNone(long renderNode);
-    @FastNative
+    @CriticalNative
     private static native boolean nHasShadow(long renderNode);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetClipToOutline(long renderNode, boolean clipToOutline);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetRevealClip(long renderNode,
             boolean shouldClip, float x, float y, float radius);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetAlpha(long renderNode, float alpha);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetHasOverlappingRendering(long renderNode,
             boolean hasOverlappingRendering);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetElevation(long renderNode, float lift);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetTranslationX(long renderNode, float translationX);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetTranslationY(long renderNode, float translationY);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetTranslationZ(long renderNode, float translationZ);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetRotation(long renderNode, float rotation);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetRotationX(long renderNode, float rotationX);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetRotationY(long renderNode, float rotationY);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetScaleX(long renderNode, float scaleX);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetScaleY(long renderNode, float scaleY);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetStaticMatrix(long renderNode, long nativeMatrix);
-    @FastNative
+    @CriticalNative
     private static native boolean nSetAnimationMatrix(long renderNode, long animationMatrix);
 
-    @FastNative
+    @CriticalNative
     private static native boolean nHasOverlappingRendering(long renderNode);
-    @FastNative
+    @CriticalNative
     private static native boolean nGetClipToOutline(long renderNode);
-    @FastNative
+    @CriticalNative
     private static native float nGetAlpha(long renderNode);
-    @FastNative
+    @CriticalNative
     private static native float nGetCameraDistance(long renderNode);
-    @FastNative
+    @CriticalNative
     private static native float nGetScaleX(long renderNode);
-    @FastNative
+    @CriticalNative
     private static native float nGetScaleY(long renderNode);
-    @FastNative
+    @CriticalNative
     private static native float nGetElevation(long renderNode);
-    @FastNative
+    @CriticalNative
     private static native float nGetTranslationX(long renderNode);
-    @FastNative
+    @CriticalNative
     private static native float nGetTranslationY(long renderNode);
-    @FastNative
+    @CriticalNative
     private static native float nGetTranslationZ(long renderNode);
-    @FastNative
+    @CriticalNative
     private static native float nGetRotation(long renderNode);
-    @FastNative
+    @CriticalNative
     private static native float nGetRotationX(long renderNode);
-    @FastNative
+    @CriticalNative
     private static native float nGetRotationY(long renderNode);
-    @FastNative
+    @CriticalNative
     private static native boolean nIsPivotExplicitlySet(long renderNode);
-    @FastNative
+    @CriticalNative
     private static native float nGetPivotX(long renderNode);
-    @FastNative
+    @CriticalNative
     private static native float nGetPivotY(long renderNode);
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 316b123..12658bd 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -128,6 +128,7 @@
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -2474,7 +2475,9 @@
      *                     1             PFLAG3_SCROLL_INDICATOR_START
      *                    1              PFLAG3_SCROLL_INDICATOR_END
      *                   1               PFLAG3_ASSIST_BLOCKED
-     *           xxxxxxxx                * NO LONGER NEEDED, SHOULD BE REUSED *
+     *                  1                PFLAG3_CLUSTER
+     *                 1                 PFLAG3_SECTION
+     *           xxxxxx                  * NO LONGER NEEDED, SHOULD BE REUSED *
      *          1                        PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE
      *         1                         PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED
      *        1                          PFLAG3_TEMPORARY_DETACH
@@ -2673,6 +2676,22 @@
     static final int PFLAG3_ASSIST_BLOCKED = 0x4000;
 
     /**
+     * Flag indicating that the view is a root of a keyboard navigation cluster.
+     *
+     * @see #isKeyboardNavigationCluster()
+     * @see #setKeyboardNavigationCluster(boolean)
+     */
+    private static final int PFLAG3_CLUSTER = 0x8000;
+
+    /**
+     * Flag indicating that the view is a root of a keyboard navigation section.
+     *
+     * @see #isKeyboardNavigationSection()
+     * @see #setKeyboardNavigationSection(boolean)
+     */
+    private static final int PFLAG3_SECTION = 0x10000;
+
+    /**
      * 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
@@ -3740,6 +3759,16 @@
      */
     int mNextFocusForwardId = View.NO_ID;
 
+    /**
+     * User-specified next keyboard navigation cluster.
+     */
+    int mNextClusterForwardId = View.NO_ID;
+
+    /**
+     * User-specified next keyboard navigation section.
+     */
+    int mNextSectionForwardId = View.NO_ID;
+
     private CheckForLongPress mPendingCheckForLongPress;
     private CheckForTap mPendingCheckForTap = null;
     private PerformClick mPerformClick;
@@ -3964,6 +3993,21 @@
     int mLayerType = LAYER_TYPE_NONE;
     Paint mLayerPaint;
 
+
+    /**
+     * <p>When setting a {@link android.app.assist.AssistStructure}, its nodes should not contain
+     * PII (Personally Identifiable Information).
+     */
+    // TODO(b/33197203) (b/33269702): improve documentation: mention all cases, show examples, etc.
+    public static final int ASSIST_FLAG_SANITIZED_TEXT = 0x1;
+
+    /**
+     * <p>When setting a {@link android.app.assist.AssistStructure}, its nodes should contain all
+     * type of data, even sensitive PII (Personally Identifiable Information) like passwords or
+     * credit card numbers.
+     */
+    public static final int ASSIST_FLAG_NON_SANITIZED_TEXT = 0x2;
+
     /**
      * Set to true when drawing cache is enabled and cannot be created.
      *
@@ -4516,6 +4560,12 @@
                 case R.styleable.View_nextFocusForward:
                     mNextFocusForwardId = a.getResourceId(attr, View.NO_ID);
                     break;
+                case R.styleable.View_nextClusterForward:
+                    mNextClusterForwardId = a.getResourceId(attr, View.NO_ID);
+                    break;
+                case R.styleable.View_nextSectionForward:
+                    mNextSectionForwardId = a.getResourceId(attr, View.NO_ID);
+                    break;
                 case R.styleable.View_minWidth:
                     mMinWidth = a.getDimensionPixelSize(attr, 0);
                     break;
@@ -4652,10 +4702,19 @@
                         forceHasOverlappingRendering(a.getBoolean(attr, true));
                     }
                     break;
-
                 case R.styleable.View_tooltip:
                     setTooltip(a.getText(attr));
                     break;
+                case R.styleable.View_keyboardNavigationCluster:
+                    if (a.peekValue(attr) != null) {
+                        setKeyboardNavigationCluster(a.getBoolean(attr, true));
+                    }
+                    break;
+                case R.styleable.View_keyboardNavigationSection:
+                    if (a.peekValue(attr) != null) {
+                        setKeyboardNavigationSection(a.getBoolean(attr, true));
+                    }
+                    break;
             }
         }
 
@@ -6781,8 +6840,35 @@
      * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}.
      * @param structure Fill in with structured view data.  The default implementation
      * fills in all data that can be inferred from the view itself.
+     *
+     * @deprecated As of API O sub-classes should override
+     * {@link #onProvideStructure(ViewStructure, int)} instead.
      */
+    // TODO(b/33197203): set proper API above
+    @Deprecated
     public void onProvideStructure(ViewStructure structure) {
+        onProvideStructure(structure, 0);
+    }
+
+    /**
+     * Called when assist structure is being retrieved from a view as part of
+     * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} or as part
+     * of an auto-fill request.
+     *
+     * <p>The default implementation fills in all data that can be inferred from the view itself.
+     *
+     * <p>The structure must be filled according to the request type, which is set in the
+     * {@code flags} parameter - see the documentation on each flag for more details.
+     *
+     * @param structure Fill in with structured view data. The default implementation
+     * fills in all data that can be inferred from the view itself.
+     * @param flags optional flags (see {@link #ASSIST_FLAG_SANITIZED_TEXT} and
+     * {@link #ASSIST_FLAG_NON_SANITIZED_TEXT} for more info).
+     */
+    public void onProvideStructure(ViewStructure structure, int flags) {
+        boolean forAutoFill = (flags
+                & (View.ASSIST_FLAG_SANITIZED_TEXT
+                        | View.ASSIST_FLAG_NON_SANITIZED_TEXT)) != 0;
         final int id = mID;
         if (id > 0 && (id&0xff000000) != 0 && (id&0x00ff0000) != 0
                 && (id&0x0000ffff) != 0) {
@@ -6800,9 +6886,11 @@
             structure.setId(id, null, null, null);
         }
 
-        // The auto-fill id needs to be unique, but its value doesn't matter, so it's better to
-        // reuse the accessibility id to save space.
-        structure.setAutoFillId(getAccessibilityViewId());
+        if (forAutoFill) {
+            // The auto-fill id needs to be unique, but its value doesn't matter, so it's better to
+            // reuse the accessibility id to save space.
+            structure.setAutoFillId(getAccessibilityViewId());
+        }
 
         structure.setDimens(mLeft, mTop, mScrollX, mScrollY, mRight - mLeft, mBottom - mTop);
         if (!hasIdentityMatrix()) {
@@ -6852,20 +6940,52 @@
      * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the
      * view's virtual accessibility nodes, if any.  You can override this for a more
      * optimal implementation providing this data.
+     *
+     * @deprecated As of API O, sub-classes should override
+     * {@link #onProvideVirtualStructure(ViewStructure, int)} instead.
      */
+    // TODO(b/33197203): set proper API above
+    @Deprecated
     public void onProvideVirtualStructure(ViewStructure structure) {
+        onProvideVirtualStructure(structure, 0);
+    }
+
+    /**
+     * Called when assist structure is being retrieved from a view as part of
+     * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} or as part
+     * of an auto-fill request to generate additional virtual structure under this view.
+     *
+     * <p>The defaullt implementation uses {@link #getAccessibilityNodeProvider()} to try to
+     * generate this from the view's virtual accessibility nodes, if any.  You can override this
+     * for a more optimal implementation providing this data.
+     *
+     * <p>The structure must be filled according to the request type, which is set in the
+     * {@code flags} parameter - see the documentation on each flag for more details.
+     *
+     * @param structure Fill in with structured view data.
+     * @param flags optional flags (see {@link #ASSIST_FLAG_SANITIZED_TEXT} and
+     * {@link #ASSIST_FLAG_NON_SANITIZED_TEXT} for more info).
+     */
+    public void onProvideVirtualStructure(ViewStructure structure, int flags) {
+        boolean sanitize = (flags & View.ASSIST_FLAG_SANITIZED_TEXT) != 0;
+
+        if (sanitize) {
+            // TODO(b/33197203): change populateVirtualStructure so it sanitizes data in this case.
+            return;
+        }
+
         AccessibilityNodeProvider provider = getAccessibilityNodeProvider();
         if (provider != null) {
             AccessibilityNodeInfo info = createAccessibilityNodeInfo();
             structure.setChildCount(1);
             ViewStructure root = structure.newChild(0);
-            populateVirtualStructure(root, provider, info);
+            populateVirtualStructure(root, provider, info, flags);
             info.recycle();
         }
     }
 
     private void populateVirtualStructure(ViewStructure structure,
-            AccessibilityNodeProvider provider, AccessibilityNodeInfo info) {
+            AccessibilityNodeProvider provider, AccessibilityNodeInfo info, int flags) {
         structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()),
                 null, null, null);
         Rect rect = structure.getTempRect();
@@ -6914,7 +7034,7 @@
                 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo(
                         AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i)));
                 ViewStructure child = structure.newChild(i);
-                populateVirtualStructure(child, provider, cinfo);
+                populateVirtualStructure(child, provider, cinfo, flags);
                 cinfo.recycle();
             }
         }
@@ -6924,11 +7044,38 @@
      * Dispatch creation of {@link ViewStructure} down the hierarchy.  The default
      * implementation calls {@link #onProvideStructure} and
      * {@link #onProvideVirtualStructure}.
+     *
+     * @deprecated As of API O,  sub-classes should override
+     * {@link #dispatchProvideStructure(ViewStructure, int)} instead.
      */
+    // TODO(b/33197203): set proper API above
+    @Deprecated
     public void dispatchProvideStructure(ViewStructure structure) {
-        if (!isAssistBlocked()) {
-            onProvideStructure(structure);
-            onProvideVirtualStructure(structure);
+        dispatchProvideStructure(structure, 0);
+    }
+
+    /**
+     * Dispatch creation of {@link ViewStructure} down the hierarchy.
+     *
+     * <p>The structure must be filled according to the request type, which is set in the
+     * {@code flags} parameter - see the documentation on each flag for more details.
+     *
+     * <p>The default implementation calls {@link #onProvideStructure(ViewStructure, int)} and
+     * {@link #onProvideVirtualStructure(ViewStructure, int)}.
+     *
+     * @param structure Fill in with structured view data.
+     * @param flags optional flags (see {@link #ASSIST_FLAG_SANITIZED_TEXT} and
+     * {@link #ASSIST_FLAG_NON_SANITIZED_TEXT} for more info).
+     */
+    public void dispatchProvideStructure(ViewStructure structure, int flags) {
+        boolean forAutoFill = (flags
+                & (View.ASSIST_FLAG_SANITIZED_TEXT
+                        | View.ASSIST_FLAG_NON_SANITIZED_TEXT)) != 0;
+
+        boolean blocked = forAutoFill ? isAutoFillBlocked() : isAssistBlocked();
+        if (!blocked) {
+            onProvideStructure(structure, flags);
+            onProvideVirtualStructure(structure, flags);
         } else {
             structure.setClassName(getAccessibilityClassName().toString());
             structure.setAssistBlocked(true);
@@ -7749,6 +7896,50 @@
     }
 
     /**
+     * Gets the id of the root of the next keyboard navigation cluster.
+     * @return The next keyboard navigation cluster ID, or {@link #NO_ID} if the framework should
+     * decide automatically.
+     *
+     * @attr ref android.R.styleable#View_nextClusterForward
+     */
+    public int getNextClusterForwardId() {
+        return mNextClusterForwardId;
+    }
+
+    /**
+     * Sets the id of the view to use as the root of the next keyboard navigation cluster.
+     * @param nextClusterForwardId The next cluster ID, or {@link #NO_ID} if the framework should
+     * decide automatically.
+     *
+     * @attr ref android.R.styleable#View_nextClusterForward
+     */
+    public void setNextClusterForwardId(int nextClusterForwardId) {
+        mNextClusterForwardId = nextClusterForwardId;
+    }
+
+    /**
+     * Gets the id of the root of the next keyboard navigation section.
+     * @return The next keyboard navigation section ID, or {@link #NO_ID} if the framework should
+     * decide automatically.
+     *
+     * @attr ref android.R.styleable#View_nextSectionForward
+     */
+    public int getNextSectionForwardId() {
+        return mNextSectionForwardId;
+    }
+
+    /**
+     * Sets the id of the view to use as the root of the next keyboard navigation section.
+     * @param nextSectionForwardId The next section ID, or {@link #NO_ID} if the framework should
+     * decide automatically.
+     *
+     * @attr ref android.R.styleable#View_nextSectionForward
+     */
+    public void setNextSectionForwardId(int nextSectionForwardId) {
+        mNextSectionForwardId = nextSectionForwardId;
+    }
+
+    /**
      * Returns the visibility of this view and all of its ancestors
      *
      * @return True if this view and all of its ancestors are {@link #VISIBLE}
@@ -8667,6 +8858,25 @@
 
     /**
      * @hide
+     * Indicates whether this view will participate in data collection through
+     * {@link ViewStructure} for auto-fill purposes.
+     *
+     * <p>If {@code true}, it will not provide any data for itself or its children.
+     * <p>If {@code false}, the normal data collection will be allowed.
+     *
+     * @return Returns {@code false} if assist data collection for auto-fill is not blocked,
+     * else {@code true}.
+     *
+     * TODO(b/33197203): update / remove javadoc tags below
+     * @see #setAssistBlocked(boolean)
+     * @attr ref android.R.styleable#View_assistBlocked
+     */
+    public boolean isAutoFillBlocked() {
+        return false; // TODO(b/33197203): properly implement it
+    }
+
+    /**
+     * @hide
      * Controls whether assist data collection from this view and its children is enabled
      * (that is, whether {@link #onProvideStructure} and
      * {@link #onProvideVirtualStructure} will be called).  The default value is false,
@@ -8825,6 +9035,76 @@
     }
 
     /**
+     * Returns whether this View is a root of a keyboard navigation cluster.
+     *
+     * @return True if this view is a root of a cluster, or false otherwise.
+     * @attr ref android.R.styleable#View_keyboardNavigationCluster
+     */
+    @ViewDebug.ExportedProperty(category = "keyboardNavigationCluster")
+    public final boolean isKeyboardNavigationCluster() {
+        return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0;
+    }
+
+    /**
+     * Set whether this view is a root of a keyboard navigation cluster.
+     *
+     * @param isCluster If true, this view is a root of a cluster.
+     *
+     * @attr ref android.R.styleable#View_keyboardNavigationCluster
+     */
+    public void setKeyboardNavigationCluster(boolean isCluster) {
+        if (isCluster) {
+            mPrivateFlags3 |= PFLAG3_CLUSTER;
+        } else {
+            mPrivateFlags3 &= ~PFLAG3_CLUSTER;
+        }
+    }
+
+    /**
+     * Returns whether this View is a root of a keyboard navigation section.
+     *
+     * @return True if this view is a root of a section, or false otherwise.
+     * @attr ref android.R.styleable#View_keyboardNavigationSection
+     */
+    @ViewDebug.ExportedProperty(category = "keyboardNavigationSection")
+    public final boolean isKeyboardNavigationSection() {
+        return (mPrivateFlags3 & PFLAG3_SECTION) != 0;
+    }
+
+    /**
+     * Set whether this view is a root of a keyboard navigation section.
+     *
+     * @param isSection If true, this view is a root of a section.
+     *
+     * @attr ref android.R.styleable#View_keyboardNavigationSection
+     */
+    public void setKeyboardNavigationSection(boolean isSection) {
+        if (isSection) {
+            mPrivateFlags3 |= PFLAG3_SECTION;
+        } else {
+            mPrivateFlags3 &= ~PFLAG3_SECTION;
+        }
+    }
+
+    /**
+     * Find the nearest keyboard navigation cluster in the specified direction.
+     * This does not actually give focus to that cluster.
+     *
+     * @param direction Direction to look
+     *
+     * @return The nearest keyboard navigation cluster in the specified direction, or null if none
+     *         can be found
+     */
+    public View keyboardNavigationClusterSearch(int direction) {
+        if (mParent != null) {
+            final View currentCluster = isKeyboardNavigationCluster() ? this : null;
+            return mParent.keyboardNavigationClusterSearch(currentCluster, direction);
+        } else {
+            return null;
+        }
+    }
+
+    /**
      * This method is the last chance for the focused view and its ancestors to
      * respond to an arrow key. This is called when the focused view did not
      * consume the key internally, nor could the view system find a new view in
@@ -8947,6 +9227,20 @@
     }
 
     /**
+     * Adds any keyboard navigation cluster roots that are descendants of this view (possibly
+     * including this view if it is a cluster root itself) to views.
+     *
+     * @param views Cluster roots found so far
+     * @param direction Direction to look
+     */
+    public void addKeyboardNavigationClusters(@NonNull Collection<View> views, int direction) {
+        if (!isKeyboardNavigationCluster()) {
+            return;
+        }
+        views.add(this);
+    }
+
+    /**
      * Finds the Views that contain given text. The containment is case insensitive.
      * The search is performed by either the text that the View renders or the content
      * description that describes the view for accessibility purposes and the view does
@@ -13780,11 +14074,6 @@
                     receiver.damageInParent();
                 }
             }
-
-            // Damage the entire IsolatedZVolume receiving this view's shadow.
-            if (isHardwareAccelerated() && getZ() != 0) {
-                damageShadowReceiver();
-            }
         }
     }
 
@@ -13812,23 +14101,6 @@
     }
 
     /**
-     * Damage area of the screen that can be covered by this View's shadow.
-     *
-     * This method will guarantee that any changes to shadows cast by a View
-     * are damaged on the screen for future redraw.
-     */
-    private void damageShadowReceiver() {
-        final AttachInfo ai = mAttachInfo;
-        if (ai != null) {
-            ViewParent p = getParent();
-            if (p != null && p instanceof ViewGroup) {
-                final ViewGroup vg = (ViewGroup) p;
-                vg.damageInParent();
-            }
-        }
-    }
-
-    /**
      * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to
      * set any flags or handle all of the cases handled by the default invalidation methods.
      * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate
@@ -13858,9 +14130,6 @@
         } else {
             damageInParent();
         }
-        if (isHardwareAccelerated() && invalidateParent && getZ() != 0) {
-            damageShadowReceiver();
-        }
     }
 
     /**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 0f8200d..7340cf7 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -59,6 +59,7 @@
 import com.android.internal.util.Predicate;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -868,10 +869,13 @@
      */
     @Override
     public View focusSearch(View focused, int direction) {
-        if (isRootNamespace()) {
+        if (isRootNamespace()
+                || isKeyboardNavigationCluster()
+                && (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD)) {
             // root namespace means we should consider ourselves the top of the
             // tree for focus searching; otherwise we could be focus searching
-            // into other tabs.  see LocalActivityManager and TabHost for more info
+            // into other tabs.  see LocalActivityManager and TabHost for more info.
+            // Cluster's root works same way for the forward and backward navigation.
             return FocusFinder.getInstance().findNextFocus(this, focused, direction);
         } else if (mParent != null) {
             return mParent.focusSearch(focused, direction);
@@ -880,6 +884,23 @@
     }
 
     @Override
+    public View keyboardNavigationClusterSearch(View currentCluster, int direction) {
+        if (isKeyboardNavigationCluster()) {
+            currentCluster = this;
+        }
+        if (isRootNamespace()) {
+            // root namespace means we should consider ourselves the top of the
+            // tree for cluster searching; otherwise we could be focus searching
+            // into other tabs.  see LocalActivityManager and TabHost for more info
+            return FocusFinder.getInstance().findNextKeyboardNavigationCluster(
+                    this, currentCluster, direction);
+        } else if (mParent != null) {
+            return mParent.keyboardNavigationClusterSearch(currentCluster, direction);
+        }
+        return null;
+    }
+
+    @Override
     public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
         return false;
     }
@@ -1086,6 +1107,12 @@
 
     @Override
     public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
+        if (isKeyboardNavigationCluster()
+                && (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD) && !hasFocus()) {
+            // A cluster cannot be focus-entered from outside using forward/backward navigation.
+            return;
+        }
+
         final int focusableCount = views.size();
 
         final int descendantFocusability = getDescendantFocusability();
@@ -1118,6 +1145,32 @@
         }
     }
 
+    @Override
+    public void addKeyboardNavigationClusters(Collection<View> views, int direction) {
+        final int focusableCount = views.size();
+
+        super.addKeyboardNavigationClusters(views, direction);
+
+        if (focusableCount != views.size()) {
+            // No need to look for clusters inside a cluster.
+            return;
+        }
+
+        if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
+            return;
+        }
+
+        final int count = mChildrenCount;
+        final View[] children = mChildren;
+
+        for (int i = 0; i < count; i++) {
+            final View child = children[i];
+            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
+                child.addKeyboardNavigationClusters(views, direction);
+            }
+        }
+    }
+
     /**
      * Set whether this ViewGroup should ignore focus requests for itself and its children.
      * If this option is enabled and the ViewGroup or a descendant currently has focus, focus
@@ -2982,7 +3035,8 @@
         final View[] children = mChildren;
         for (int i = index; i != end; i += increment) {
             View child = children[i];
-            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
+            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
+                    && !child.isKeyboardNavigationCluster()) {
                 if (child.requestFocus(direction, previouslyFocusedRect)) {
                     return true;
                 }
@@ -3083,14 +3137,22 @@
     }
 
     /**
-     * Dispatch creation of {@link ViewStructure} down the hierarchy.  This implementation
-     * adds in all child views of the view group, in addition to calling the default View
-     * implementation.
+     * {@inheritDoc}
+     *
+     * <p>This implementation adds in all child views of the view group, in addition to calling the
+     * default {@link View} implementation.
      */
     @Override
-    public void dispatchProvideStructure(ViewStructure structure) {
-        super.dispatchProvideStructure(structure);
-        if (!isAssistBlocked()) {
+    public void dispatchProvideStructure(ViewStructure structure, int flags) {
+        super.dispatchProvideStructure(structure, flags);
+
+        boolean forAutoFill = (flags
+                & (View.ASSIST_FLAG_SANITIZED_TEXT
+                        | View.ASSIST_FLAG_NON_SANITIZED_TEXT)) != 0;
+
+        boolean blocked = forAutoFill ? isAutoFillBlocked() : isAssistBlocked();
+
+        if (!blocked) {
             if (structure.getChildCount() == 0) {
                 final int childrenCount = getChildCount();
                 if (childrenCount > 0) {
@@ -3151,7 +3213,14 @@
                         final View child = getAndVerifyPreorderedView(
                                 preorderedList, children, childIndex);
                         final ViewStructure cstructure = structure.newChild(i);
-                        child.dispatchProvideStructure(cstructure);
+
+                        // Must explicitly check which recursive method to call because child might
+                        // not be overriding the new, flags-based version
+                        if (flags == 0) {
+                            child.dispatchProvideStructure(cstructure);
+                        } else {
+                            child.dispatchProvideStructure(cstructure, flags);
+                        }
                     }
                     if (preorderedList != null) preorderedList.clear();
                 }
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 849c8b9..79b05cd 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -147,6 +147,19 @@
     public View focusSearch(View v, int direction);
 
     /**
+     * Find the nearest keyboard navigation cluster in the specified direction.
+     * This does not actually give focus to that cluster.
+     *
+     * @param currentCluster The starting point of the search. Null means the current cluster is not
+     *                       found yet
+     * @param direction Direction to look
+     *
+     * @return The nearest keyboard navigation cluster in the specified direction, or null if none
+     *         can be found
+     */
+    View keyboardNavigationClusterSearch(View currentCluster, int direction);
+
+    /**
      * Change the z order of the child so it's on top of all other children.
      * This ordering change may affect layout, if this container
      * uses an order-dependent layout scheme (e.g., LinearLayout). Prior
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e030e76..2cebeed 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -4324,6 +4324,87 @@
             super.onDeliverToNext(q);
         }
 
+        private boolean performFocusNavigation(KeyEvent event) {
+            int direction = 0;
+            switch (event.getKeyCode()) {
+                case KeyEvent.KEYCODE_DPAD_LEFT:
+                    if (event.hasNoModifiers()) {
+                        direction = View.FOCUS_LEFT;
+                    }
+                    break;
+                case KeyEvent.KEYCODE_DPAD_RIGHT:
+                    if (event.hasNoModifiers()) {
+                        direction = View.FOCUS_RIGHT;
+                    }
+                    break;
+                case KeyEvent.KEYCODE_DPAD_UP:
+                    if (event.hasNoModifiers()) {
+                        direction = View.FOCUS_UP;
+                    }
+                    break;
+                case KeyEvent.KEYCODE_DPAD_DOWN:
+                    if (event.hasNoModifiers()) {
+                        direction = View.FOCUS_DOWN;
+                    }
+                    break;
+                case KeyEvent.KEYCODE_TAB:
+                    if (event.hasNoModifiers()) {
+                        direction = View.FOCUS_FORWARD;
+                    } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
+                        direction = View.FOCUS_BACKWARD;
+                    }
+                    break;
+            }
+            if (direction != 0) {
+                View focused = mView.findFocus();
+                if (focused != null) {
+                    View v = focused.focusSearch(direction);
+                    if (v != null && v != focused) {
+                        // do the math the get the interesting rect
+                        // of previous focused into the coord system of
+                        // newly focused view
+                        focused.getFocusedRect(mTempRect);
+                        if (mView instanceof ViewGroup) {
+                            ((ViewGroup) mView).offsetDescendantRectToMyCoords(
+                                    focused, mTempRect);
+                            ((ViewGroup) mView).offsetRectIntoDescendantCoords(
+                                    v, mTempRect);
+                        }
+                        if (v.requestFocus(direction, mTempRect)) {
+                            playSoundEffect(SoundEffectConstants
+                                    .getContantForFocusDirection(direction));
+                            return true;
+                        }
+                    }
+
+                    // Give the focused view a last chance to handle the dpad key.
+                    if (mView.dispatchUnhandledMove(focused, direction)) {
+                        return true;
+                    }
+                } else {
+                    // find the best view to give focus to in this non-touch-mode with no-focus
+                    View v = focusSearch(null, direction);
+                    if (v != null && v.requestFocus(direction)) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        private boolean performClusterNavigation(int direction) {
+            final View focused = mView.findFocus();
+            final View cluster = focused != null
+                    ? focused.keyboardNavigationClusterSearch(direction)
+                    : keyboardNavigationClusterSearch(null, direction);
+
+            if (cluster != null && cluster.requestFocus()) {
+                return true;
+            }
+
+            return false;
+        }
+
         private int processKeyEvent(QueuedInputEvent q) {
             final KeyEvent event = (KeyEvent)q.mEvent;
 
@@ -4336,11 +4417,26 @@
                 return FINISH_NOT_HANDLED;
             }
 
+            int clusterNavigationDirection = 0;
+
+            if (event.getAction() == KeyEvent.ACTION_DOWN && event.isCtrlPressed()) {
+                final int character =
+                        event.getUnicodeChar(event.getMetaState() & ~KeyEvent.META_CTRL_MASK);
+                if (character == '+') {
+                    clusterNavigationDirection = View.FOCUS_FORWARD;
+                }
+
+                if (character == '_') {
+                    clusterNavigationDirection = View.FOCUS_BACKWARD;
+                }
+            }
+
             // If the Control modifier is held, try to interpret the key as a shortcut.
             if (event.getAction() == KeyEvent.ACTION_DOWN
                     && event.isCtrlPressed()
                     && event.getRepeatCount() == 0
-                    && !KeyEvent.isModifierKey(event.getKeyCode())) {
+                    && !KeyEvent.isModifierKey(event.getKeyCode())
+                    && clusterNavigationDirection == 0) {
                 if (mView.dispatchKeyShortcutEvent(event)) {
                     return FINISH_HANDLED;
                 }
@@ -4359,68 +4455,13 @@
 
             // Handle automatic focus changes.
             if (event.getAction() == KeyEvent.ACTION_DOWN) {
-                int direction = 0;
-                switch (event.getKeyCode()) {
-                    case KeyEvent.KEYCODE_DPAD_LEFT:
-                        if (event.hasNoModifiers()) {
-                            direction = View.FOCUS_LEFT;
-                        }
-                        break;
-                    case KeyEvent.KEYCODE_DPAD_RIGHT:
-                        if (event.hasNoModifiers()) {
-                            direction = View.FOCUS_RIGHT;
-                        }
-                        break;
-                    case KeyEvent.KEYCODE_DPAD_UP:
-                        if (event.hasNoModifiers()) {
-                            direction = View.FOCUS_UP;
-                        }
-                        break;
-                    case KeyEvent.KEYCODE_DPAD_DOWN:
-                        if (event.hasNoModifiers()) {
-                            direction = View.FOCUS_DOWN;
-                        }
-                        break;
-                    case KeyEvent.KEYCODE_TAB:
-                        if (event.hasNoModifiers()) {
-                            direction = View.FOCUS_FORWARD;
-                        } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
-                            direction = View.FOCUS_BACKWARD;
-                        }
-                        break;
-                }
-                if (direction != 0) {
-                    View focused = mView.findFocus();
-                    if (focused != null) {
-                        View v = focused.focusSearch(direction);
-                        if (v != null && v != focused) {
-                            // do the math the get the interesting rect
-                            // of previous focused into the coord system of
-                            // newly focused view
-                            focused.getFocusedRect(mTempRect);
-                            if (mView instanceof ViewGroup) {
-                                ((ViewGroup) mView).offsetDescendantRectToMyCoords(
-                                        focused, mTempRect);
-                                ((ViewGroup) mView).offsetRectIntoDescendantCoords(
-                                        v, mTempRect);
-                            }
-                            if (v.requestFocus(direction, mTempRect)) {
-                                playSoundEffect(SoundEffectConstants
-                                        .getContantForFocusDirection(direction));
-                                return FINISH_HANDLED;
-                            }
-                        }
-
-                        // Give the focused view a last chance to handle the dpad key.
-                        if (mView.dispatchUnhandledMove(focused, direction)) {
-                            return FINISH_HANDLED;
-                        }
-                    } else {
-                        // find the best view to give focus to in this non-touch-mode with no-focus
-                        View v = focusSearch(null, direction);
-                        if (v != null && v.requestFocus(direction)) {
-                            return FINISH_HANDLED;
-                        }
+                if (clusterNavigationDirection != 0) {
+                    if (performClusterNavigation(clusterNavigationDirection)) {
+                        return FINISH_HANDLED;
+                    }
+                } else {
+                    if (performFocusNavigation(event)) {
+                        return FINISH_HANDLED;
                     }
                 }
             }
@@ -5842,6 +5883,19 @@
         return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public View keyboardNavigationClusterSearch(View currentCluster, int direction) {
+        checkThread();
+        if (!(mView instanceof ViewGroup)) {
+            return null;
+        }
+        return FocusFinder.getInstance().findNextKeyboardNavigationCluster(
+                (ViewGroup) mView, currentCluster, direction);
+    }
+
     public void debug() {
         mView.debug();
     }
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index 7dd2fc2..e4d4e7b 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -385,6 +385,14 @@
             }
         }
 
+        if (observer.mOnDrawListeners != null) {
+            if (mOnDrawListeners != null) {
+                mOnDrawListeners.addAll(observer.mOnDrawListeners);
+            } else {
+                mOnDrawListeners = observer.mOnDrawListeners;
+            }
+        }
+
         if (observer.mOnTouchModeChangeListeners != null) {
             if (mOnTouchModeChangeListeners != null) {
                 mOnTouchModeChangeListeners.addAll(observer.mOnTouchModeChangeListeners);
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 8084195..13d5b85 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -350,7 +350,18 @@
                 return;
             }
             if (!mIsEnabled) {
-                throw new IllegalStateException("Accessibility off. Did you forget to check that?");
+                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, "Interrupt called with accessibility disabled");
+                    return;
+                }
             }
             userId = mUserId;
         }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index b840f4a..8ecc42d 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2504,6 +2504,7 @@
         return mProvider.getViewDelegate().shouldDelayChildPressedState();
     }
 
+    @Override
     public CharSequence getAccessibilityClassName() {
         return WebView.class.getName();
     }
@@ -2513,6 +2514,11 @@
         mProvider.getViewDelegate().onProvideVirtualStructure(structure);
     }
 
+    @Override
+    public void onProvideVirtualStructure(ViewStructure structure, int flags) {
+        mProvider.getViewDelegate().onProvideVirtualStructure(structure, flags);
+    }
+
     /** @hide */
     @Override
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 95ec179..7b95180 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -311,6 +311,11 @@
 
         public void onProvideVirtualStructure(android.view.ViewStructure structure);
 
+        @SuppressWarnings("unused")
+        public default void onProvideVirtualStructure(android.view.ViewStructure structure,
+                int flags) {
+        }
+
         public AccessibilityNodeProvider getAccessibilityNodeProvider();
 
         public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info);
diff --git a/core/java/android/widget/Chronometer.java b/core/java/android/widget/Chronometer.java
index b9224f3..444ebc5 100644
--- a/core/java/android/widget/Chronometer.java
+++ b/core/java/android/widget/Chronometer.java
@@ -17,8 +17,11 @@
 package android.widget;
 
 import android.content.Context;
-import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.icu.text.MeasureFormat;
+import android.icu.text.MeasureFormat.FormatWidth;
+import android.icu.util.Measure;
+import android.icu.util.MeasureUnit;
 import android.os.SystemClock;
 import android.text.format.DateUtils;
 import android.util.AttributeSet;
@@ -28,6 +31,7 @@
 
 import com.android.internal.R;
 
+import java.util.ArrayList;
 import java.util.Formatter;
 import java.util.IllegalFormatException;
 import java.util.Locale;
@@ -329,9 +333,6 @@
     private static final int MIN_IN_SEC = 60;
     private static final int HOUR_IN_SEC = MIN_IN_SEC*60;
     private static String formatDuration(long ms) {
-        final Resources res = Resources.getSystem();
-        final StringBuilder text = new StringBuilder();
-
         int duration = (int) (ms / DateUtils.SECOND_IN_MILLIS);
         if (duration < 0) {
             duration = -duration;
@@ -348,31 +349,19 @@
             m = duration / MIN_IN_SEC;
             duration -= m * MIN_IN_SEC;
         }
-        int s = duration;
+        final int s = duration;
 
-        try {
-            if (h > 0) {
-                text.append(res.getQuantityString(
-                        com.android.internal.R.plurals.duration_hours, h, h));
-            }
-            if (m > 0) {
-                if (text.length() > 0) {
-                    text.append(' ');
-                }
-                text.append(res.getQuantityString(
-                        com.android.internal.R.plurals.duration_minutes, m, m));
-            }
-
-            if (text.length() > 0) {
-                text.append(' ');
-            }
-            text.append(res.getQuantityString(
-                    com.android.internal.R.plurals.duration_seconds, s, s));
-        } catch (Resources.NotFoundException e) {
-            // Ignore; plurals throws an exception for an untranslated quantity for a given locale.
-            return null;
+        final ArrayList<Measure> measures = new ArrayList<Measure>();
+        if (h > 0) {
+            measures.add(new Measure(h, MeasureUnit.HOUR));
         }
-        return text.toString();
+        if (m > 0) {
+            measures.add(new Measure(m, MeasureUnit.MINUTE));
+        }
+        measures.add(new Measure(s, MeasureUnit.SECOND));
+
+        return MeasureFormat.getInstance(Locale.getDefault(), FormatWidth.WIDE)
+                    .formatMeasures((Measure[]) measures.toArray());
     }
 
     @Override
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index fcc1667..e629df9 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -1404,8 +1404,10 @@
     }
 
     @Override
-    public void onProvideStructure(ViewStructure structure) {
-        super.onProvideStructure(structure);
+    public void onProvideStructure(ViewStructure structure, int flags) {
+        super.onProvideStructure(structure, flags);
+
+        // NOTE: current there is no difference for Assist (flags=0) or AutoFill (flags>0);
         CharSequence switchText = isChecked() ? mTextOn : mTextOff;
         if (!TextUtils.isEmpty(switchText)) {
             CharSequence oldText = structure.getText();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 44655f1..1961bf6 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -77,6 +77,7 @@
 import android.text.SpannedString;
 import android.text.StaticLayout;
 import android.text.TextAssistant;
+import android.text.TextClassificationManager;
 import android.text.TextDirectionHeuristic;
 import android.text.TextDirectionHeuristics;
 import android.text.TextPaint;
@@ -680,8 +681,6 @@
     private static final int DEFAULT_AUTO_SIZE_GRANULARITY_IN_PX = 1;
     // Contains the sorted set of desired text sizes in pixels to pick from when auto-sizing text.
     private int[] mAutoSizeTextSizesInPx;
-    // Specifies if the current TextView needs to be auto-sized.
-    private boolean mNeedsTextAutoResize = false;
 
     /**
      * Kick-start the font cache for the zygote process (to pay the cost of
@@ -1561,7 +1560,6 @@
                     }
 
                     Arrays.sort(mAutoSizeTextSizesInPx);
-                    mNeedsTextAutoResize = true;
                     break;
                 default:
                     throw new IllegalArgumentException(
@@ -7524,7 +7522,7 @@
             scrollTo(0, 0);
         }
 
-        if (mNeedsTextAutoResize) {
+        if (isAutoSizeEnabled()) {
             // Call auto-size after the width and height have been calculated.
             autoSizeText();
         }
@@ -7536,20 +7534,21 @@
      * Automatically computes and sets the text size.
      */
     private void autoSizeText() {
+        final int maxWidth = getMeasuredWidth() - getTotalPaddingLeft() - getTotalPaddingRight();
+        final int maxHeight = getMeasuredHeight() - getTotalPaddingBottom() - getTotalPaddingTop();
+
+        if (maxWidth <= 0 || maxHeight <= 0) {
+            return;
+        }
+
         synchronized (TEMP_RECTF) {
             TEMP_RECTF.setEmpty();
-            final int maxWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
-            final int maxHeight = getMeasuredHeight() - getPaddingBottom() - getPaddingTop();
-
-            if (maxWidth <= 0 || maxHeight <= 0) {
-                return;
-            }
-
             TEMP_RECTF.right = maxWidth;
             TEMP_RECTF.bottom = maxHeight;
             final float textSize = findLargestTextSizeWhichFits(TEMP_RECTF);
-            setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
-            mNeedsTextAutoResize = false;
+            if (textSize != getTextSize()) {
+                setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
+            }
         }
     }
 
@@ -7594,13 +7593,12 @@
 
         if ((mLayout instanceof BoringLayout) && BoringLayout.isBoring(
                 text, mTempTextPaint, getTextDirectionHeuristic(), mBoring) != null) {
-            return mTempTextPaint.getFontSpacing() + getPaddingTop() + getPaddingBottom()
-                    <= availableSpace.bottom
-                    && mTempTextPaint.measureText(text, 0, text.length())
-                    + getPaddingLeft() + getPaddingRight() <= availableSpace.right;
+            return mTempTextPaint.getFontSpacing() <= availableSpace.bottom
+                    && mTempTextPaint.measureText(text, 0, text.length()) <= availableSpace.right;
         } else {
             StaticLayout.Builder layoutBuilder = StaticLayout.Builder.obtain(text, 0, text.length(),
-                    mTempTextPaint, getMeasuredWidth() - getPaddingLeft() - getPaddingRight());
+                    mTempTextPaint,
+                    getMeasuredWidth() - getTotalPaddingLeft() - getTotalPaddingRight());
             layoutBuilder.setAlignment(getLayoutAlignment());
             layoutBuilder.setLineSpacing(getLineSpacingExtra(), getLineSpacingMultiplier());
             layoutBuilder.setIncludePad(true);
@@ -9270,7 +9268,15 @@
     }
 
     /**
-     * @return {@code true} if this TextView supports autosizing text to fit within its container.
+     * @return {@code true} if this widget supports auto-sizing text and has been configured to
+     * auto-size.
+     */
+    private boolean isAutoSizeEnabled() {
+        return supportsAutoSizeText() && mAutoSizeType != AUTO_SIZE_TYPE_NONE;
+    }
+
+    /**
+     * @return {@code true} if this TextView supports auto-sizing text to fit within its container.
      * @hide
      */
     protected boolean supportsAutoSizeText() {
@@ -9385,11 +9391,14 @@
     }
 
     @Override
-    public void onProvideStructure(ViewStructure structure) {
-        super.onProvideStructure(structure);
+    public void onProvideStructure(ViewStructure structure, int flags) {
+        super.onProvideStructure(structure, flags);
+
+        final boolean forAutoFillSave =
+                (flags & ASSIST_FLAG_NON_SANITIZED_TEXT) != 0;
         final boolean isPassword = hasPasswordTransformationMethod()
                 || isPasswordInputType(getInputType());
-        if (!isPassword) {
+        if (!isPassword || forAutoFillSave) {
             if (mLayout == null) {
                 assumeLayout();
             }
@@ -10027,8 +10036,8 @@
             mTextAssistant = ((Activity) mContext).getTextAssistant();
         } else {
             // The context of this TextView should be an Activity. If it is not and no
-            // text assistant has been set, return a NO_OP TextAssistant.
-            mTextAssistant = TextAssistant.NO_OP;
+            // text assistant has been set, return the TextClassificationManager.
+            mTextAssistant = mContext.getSystemService(TextClassificationManager.class);
         }
         return  mTextAssistant;
     }
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index d8f7907..c314cae 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -19,6 +19,7 @@
 import android.animation.ObjectAnimator;
 import android.annotation.NonNull;
 import android.app.Activity;
+import android.app.usage.UsageStatsManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -299,6 +300,11 @@
                 || aInfo.name.equals(IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE)) {
             result = Intent.createChooser(result,
                     getIntent().getCharSequenceExtra(Intent.EXTRA_TITLE));
+
+            // Don't auto-launch single intents if the intent is being forwarded. This is done
+            // because automatically launching a resolving application as a response to the user
+            // action of switching accounts is pretty unexpected.
+            result.putExtra(Intent.EXTRA_AUTO_LAUNCH_SINGLE_CHOICE, false);
         }
         return result;
     }
@@ -398,6 +404,7 @@
                 }
             }
         }
+        updateChooserCounts(target, mContentType);
         return super.onTargetSelected(target, alwaysCheck);
     }
 
@@ -542,20 +549,46 @@
         // Do nothing. We'll send the voice stuff ourselves.
     }
 
+    void updateChooserCounts(TargetInfo info, String annotation) {
+        if (info != null) {
+            UsageStatsManager usageStatsManager =
+                    (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
+            if (usageStatsManager == null) {
+                if (DEBUG) {
+                    Log.d(TAG, "Can not start UsageStatsManager");
+                }
+                return;
+            }
+            final ResolveInfo ri = info.getResolveInfo();
+            if (ri != null && ri.activityInfo != null) {
+                usageStatsManager.reportChooserSelection(ri.activityInfo.packageName, getUserId(),
+                        annotation, null, info.getResolvedIntent().getAction());
+                if (DEBUG) {
+                    Log.d(TAG, "ResolveInfo Package is" + ri.activityInfo.packageName);
+                }
+            } else if(DEBUG) {
+                Log.d(TAG, "Can not log Chooser Counts of null ResovleInfo");
+            }
+        }
+    }
+
     void onRefinementResult(TargetInfo selectedTarget, Intent matchingIntent) {
         if (mRefinementResultReceiver != null) {
             mRefinementResultReceiver.destroy();
             mRefinementResultReceiver = null;
         }
-
         if (selectedTarget == null) {
             Log.e(TAG, "Refinement result intent did not match any known targets; canceling");
         } else if (!checkTargetSourceIntent(selectedTarget, matchingIntent)) {
             Log.e(TAG, "onRefinementResult: Selected target " + selectedTarget
                     + " cannot match refined source intent " + matchingIntent);
-        } else if (super.onTargetSelected(selectedTarget.cloneFilledIn(matchingIntent, 0), false)) {
-            finish();
-            return;
+        } else {
+            TargetInfo clonedTarget = selectedTarget.cloneFilledIn(matchingIntent, 0);
+            if (super.onTargetSelected(clonedTarget, false)) {
+                updateChooserCounts(clonedTarget, mContentType);
+                finish();
+                return;
+            }
         }
         onRefinementCanceled();
     }
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index dd8ef18..c516b5c 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -26,6 +26,7 @@
 import android.app.VoiceInteractor.Prompt;
 import android.content.pm.ComponentInfo;
 import android.os.AsyncTask;
+import android.os.RemoteException;
 import android.provider.MediaStore;
 import android.provider.Settings;
 import android.text.TextUtils;
@@ -53,7 +54,6 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.PatternMatcher;
-import android.os.RemoteException;
 import android.os.StrictMode;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -114,6 +114,7 @@
     private ComponentName[] mFilteredComponents;
 
     protected ResolverDrawerLayout mResolverDrawerLayout;
+    protected String mContentType;
 
     private boolean mRegistered;
     private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@@ -270,6 +271,7 @@
         final String referrerPackage = getReferrerPackageName();
 
         mResolverComparator = new ResolverComparator(this, getTargetIntent(), referrerPackage);
+        mContentType = mResolverComparator.mContentType;
 
         if (configureContentView(mIntents, initialIntents, rList, alwaysUseOption)) {
             return;
diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java
index 4d4c7ce..75be906 100644
--- a/core/java/com/android/internal/app/ResolverComparator.java
+++ b/core/java/com/android/internal/app/ResolverComparator.java
@@ -63,6 +63,8 @@
     private final long mSinceTime;
     private final LinkedHashMap<ComponentName, ScoredTarget> mScoredTargets = new LinkedHashMap<>();
     private final String mReferrerPackage;
+    public String mContentType;
+    private String mAction;
 
     public ResolverComparator(Context context, Intent intent, String referrerPackage) {
         mCollator = Collator.getInstance(context.getResources().getConfiguration().locale);
@@ -76,6 +78,8 @@
         mCurrentTime = System.currentTimeMillis();
         mSinceTime = mCurrentTime - USAGE_STATS_PERIOD;
         mStats = mUsm.queryAndAggregateUsageStats(mSinceTime, mCurrentTime);
+        mContentType = intent.getType();
+        mAction = intent.getAction();
     }
 
     public void compute(List<ResolvedComponentInfo> targets) {
@@ -86,6 +90,7 @@
         long mostRecentlyUsedTime = recentSinceTime + 1;
         long mostTimeSpent = 1;
         int mostLaunched = 1;
+        int mostSelected = 1;
 
         for (ResolvedComponentInfo target : targets) {
             final ScoredTarget scoredTarget
@@ -114,6 +119,25 @@
                 if (launched > mostLaunched) {
                     mostLaunched = launched;
                 }
+                // TODO(kanlig): get and combine counts of categories.
+
+                int selected = 0;
+                if (pkStats.mChooserCounts != null && mAction != null
+                        && pkStats.mChooserCounts.get(mAction) != null) {
+                    selected = pkStats.mChooserCounts.get(mAction).getOrDefault(mContentType, 0);
+                }
+                if (DEBUG) {
+                    if (mAction == null) {
+                        Log.d(TAG, "Action type is null");
+                    } else {
+                        Log.d(TAG, "Chooser Count of " + mAction + ":" +
+                                target.name.getPackageName() + " is " + Integer.toString(selected));
+                    }
+                }
+                scoredTarget.chooserCount = selected;
+                if (selected > mostSelected) {
+                    mostSelected = selected;
+                }
             }
         }
 
@@ -190,7 +214,15 @@
                         lhs.activityInfo.packageName, lhs.activityInfo.name));
                 final ScoredTarget rhsTarget = mScoredTargets.get(new ComponentName(
                         rhs.activityInfo.packageName, rhs.activityInfo.name));
-                final float diff = rhsTarget.score - lhsTarget.score;
+
+                final int chooserCountDiff = Long.compare(
+                        rhsTarget.chooserCount, lhsTarget.chooserCount);
+
+                if (chooserCountDiff != 0) {
+                    return chooserCountDiff > 0 ? 1 : -1;
+                }
+
+                final int diff = Float.compare(rhsTarget.score, lhsTarget.score);
 
                 if (diff != 0) {
                     return diff > 0 ? 1 : -1;
@@ -220,6 +252,7 @@
         public long lastTimeUsed;
         public long timeSpent;
         public long launchCount;
+        public long chooserCount;
 
         public ScoredTarget(ComponentInfo ci) {
             componentInfo = ci;
@@ -232,6 +265,7 @@
                     + " lastTimeUsed: " + lastTimeUsed
                     + " timeSpent: " + timeSpent
                     + " launchCount: " + launchCount
+                    + " chooserCount: " + chooserCount
                     + "}";
         }
     }
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index f479f4f..83b7d2f 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -76,6 +76,7 @@
         final long[] apkHandles;
         final boolean multiArch;
         final boolean extractNativeLibs;
+        final boolean debuggable;
 
         public static Handle create(File packageFile) throws IOException {
             try {
@@ -89,15 +90,17 @@
         public static Handle create(Package pkg) throws IOException {
             return create(pkg.getAllCodePaths(),
                     (pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0,
-                    (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) != 0);
+                    (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) != 0,
+                    (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
         }
 
         public static Handle create(PackageLite lite) throws IOException {
-            return create(lite.getAllCodePaths(), lite.multiArch, lite.extractNativeLibs);
+            return create(lite.getAllCodePaths(), lite.multiArch, lite.extractNativeLibs,
+                    lite.debuggable);
         }
 
         private static Handle create(List<String> codePaths, boolean multiArch,
-                boolean extractNativeLibs) throws IOException {
+                boolean extractNativeLibs, boolean debuggable) throws IOException {
             final int size = codePaths.size();
             final long[] apkHandles = new long[size];
             for (int i = 0; i < size; i++) {
@@ -112,13 +115,15 @@
                 }
             }
 
-            return new Handle(apkHandles, multiArch, extractNativeLibs);
+            return new Handle(apkHandles, multiArch, extractNativeLibs, debuggable);
         }
 
-        Handle(long[] apkHandles, boolean multiArch, boolean extractNativeLibs) {
+        Handle(long[] apkHandles, boolean multiArch, boolean extractNativeLibs,
+                boolean debuggable) {
             this.apkHandles = apkHandles;
             this.multiArch = multiArch;
             this.extractNativeLibs = extractNativeLibs;
+            this.debuggable = debuggable;
             mGuard.open("close");
         }
 
@@ -149,15 +154,17 @@
     private static native long nativeOpenApk(String path);
     private static native void nativeClose(long handle);
 
-    private static native long nativeSumNativeBinaries(long handle, String cpuAbi);
+    private static native long nativeSumNativeBinaries(long handle, String cpuAbi,
+            boolean debuggable);
 
     private native static int nativeCopyNativeBinaries(long handle, String sharedLibraryPath,
-            String abiToCopy, boolean extractNativeLibs, boolean hasNativeBridge);
+            String abiToCopy, boolean extractNativeLibs, boolean hasNativeBridge,
+            boolean debuggable);
 
     private static long sumNativeBinaries(Handle handle, String abi) {
         long sum = 0;
         for (long apkHandle : handle.apkHandles) {
-            sum += nativeSumNativeBinaries(apkHandle, abi);
+            sum += nativeSumNativeBinaries(apkHandle, abi, handle.debuggable);
         }
         return sum;
     }
@@ -173,7 +180,7 @@
     public static int copyNativeBinaries(Handle handle, File sharedLibraryDir, String abi) {
         for (long apkHandle : handle.apkHandles) {
             int res = nativeCopyNativeBinaries(apkHandle, sharedLibraryDir.getPath(), abi,
-                    handle.extractNativeLibs, HAS_NATIVE_BRIDGE);
+                    handle.extractNativeLibs, HAS_NATIVE_BRIDGE, handle.debuggable);
             if (res != INSTALL_SUCCEEDED) {
                 return res;
             }
@@ -191,7 +198,7 @@
     public static int findSupportedAbi(Handle handle, String[] supportedAbis) {
         int finalRes = NO_NATIVE_LIBRARIES;
         for (long apkHandle : handle.apkHandles) {
-            final int res = nativeFindSupportedAbi(apkHandle, supportedAbis);
+            final int res = nativeFindSupportedAbi(apkHandle, supportedAbis, handle.debuggable);
             if (res == NO_NATIVE_LIBRARIES) {
                 // No native code, keep looking through all APKs.
             } else if (res == INSTALL_FAILED_NO_MATCHING_ABIS) {
@@ -213,7 +220,8 @@
         return finalRes;
     }
 
-    private native static int nativeFindSupportedAbi(long handle, String[] supportedAbis);
+    private native static int nativeFindSupportedAbi(long handle, String[] supportedAbis,
+            boolean debuggable);
 
     // Convenience method to call removeNativeBinariesFromDirLI(File)
     public static void removeNativeBinariesLI(String nativeLibraryPath) {
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index 98d87d3..eec3cb0 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -16,8 +16,6 @@
 
 package com.android.internal.content;
 
-import static android.net.TrafficStats.MB_IN_BYTES;
-
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
@@ -38,7 +36,7 @@
 import android.util.ArraySet;
 import android.util.Log;
 
-import libcore.io.IoUtils;
+import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -50,6 +48,11 @@
 import java.util.zip.ZipFile;
 import java.util.zip.ZipOutputStream;
 
+import libcore.io.IoUtils;
+
+import static android.net.TrafficStats.MB_IN_BYTES;
+import static android.os.storage.VolumeInfo.ID_PRIVATE_INTERNAL;
+
 /**
  * Constants used internally between the PackageManager
  * and media container service transports.
@@ -74,6 +77,8 @@
     public static final int APP_INSTALL_INTERNAL = 1;
     public static final int APP_INSTALL_EXTERNAL = 2;
 
+    private static TestableInterface sDefaultTestableInterface = null;
+
     public static IStorageManager getStorageManager() throws RemoteException {
         IBinder service = ServiceManager.getService("mount");
         if (service != null) {
@@ -338,6 +343,65 @@
     }
 
     /**
+     * A group of external dependencies used in
+     * {@link #resolveInstallVolume(Context, String, int, long)}. It can be backed by real values
+     * from the system or mocked ones for testing purposes.
+     */
+    public static abstract class TestableInterface {
+        abstract public StorageManager getStorageManager(Context context);
+        abstract public boolean getForceAllowOnExternalSetting(Context context);
+        abstract public boolean getAllow3rdPartyOnInternalConfig(Context context);
+        abstract public ApplicationInfo getExistingAppInfo(Context context, String packageName);
+        abstract public File getDataDirectory();
+
+        public boolean fitsOnInternalStorage(Context context, long sizeBytes) {
+            StorageManager storage = getStorageManager(context);
+            File target = getDataDirectory();
+            return (sizeBytes <= storage.getStorageBytesUntilLow(target));
+        }
+    }
+
+    private synchronized static TestableInterface getDefaultTestableInterface() {
+        if (sDefaultTestableInterface == null) {
+            sDefaultTestableInterface = new TestableInterface() {
+                @Override
+                public StorageManager getStorageManager(Context context) {
+                    return context.getSystemService(StorageManager.class);
+                }
+
+                @Override
+                public boolean getForceAllowOnExternalSetting(Context context) {
+                    return Settings.Global.getInt(context.getContentResolver(),
+                            Settings.Global.FORCE_ALLOW_ON_EXTERNAL, 0) != 0;
+                }
+
+                @Override
+                public boolean getAllow3rdPartyOnInternalConfig(Context context) {
+                    return context.getResources().getBoolean(
+                            com.android.internal.R.bool.config_allow3rdPartyAppOnInternal);
+                }
+
+                @Override
+                public ApplicationInfo getExistingAppInfo(Context context, String packageName) {
+                    ApplicationInfo existingInfo = null;
+                    try {
+                        existingInfo = context.getPackageManager().getApplicationInfo(packageName,
+                                PackageManager.MATCH_ANY_USER);
+                    } catch (NameNotFoundException ignored) {
+                    }
+                    return existingInfo;
+                }
+
+                @Override
+                public File getDataDirectory() {
+                    return Environment.getDataDirectory();
+                }
+            };
+        }
+        return sDefaultTestableInterface;
+    }
+
+    /**
      * Given a requested {@link PackageInfo#installLocation} and calculated
      * install size, pick the actual volume to install the app. Only considers
      * internal and private volumes, and prefers to keep an existing package on
@@ -348,25 +412,44 @@
      */
     public static String resolveInstallVolume(Context context, String packageName,
             int installLocation, long sizeBytes) throws IOException {
-        final boolean forceAllowOnExternal = Settings.Global.getInt(
-                context.getContentResolver(), Settings.Global.FORCE_ALLOW_ON_EXTERNAL, 0) != 0;
+        TestableInterface testableInterface = getDefaultTestableInterface();
+        return resolveInstallVolume(context, packageName,
+                installLocation, sizeBytes, testableInterface);
+    }
+
+    @VisibleForTesting
+    public static String resolveInstallVolume(Context context, String packageName,
+            int installLocation, long sizeBytes, TestableInterface testInterface)
+            throws IOException {
+        final boolean forceAllowOnExternal = testInterface.getForceAllowOnExternalSetting(context);
+        final boolean allow3rdPartyOnInternal =
+                testInterface.getAllow3rdPartyOnInternalConfig(context);
         // TODO: handle existing apps installed in ASEC; currently assumes
         // they'll end up back on internal storage
-        ApplicationInfo existingInfo = null;
-        try {
-            existingInfo = context.getPackageManager().getApplicationInfo(packageName,
-                    PackageManager.MATCH_ANY_USER);
-        } catch (NameNotFoundException ignored) {
+        ApplicationInfo existingInfo = testInterface.getExistingAppInfo(context, packageName);
+
+        final boolean fitsOnInternal = testInterface.fitsOnInternalStorage(context, sizeBytes);
+        final StorageManager storageManager =
+                testInterface.getStorageManager(context);
+
+        // System apps always forced to internal storage
+        if (existingInfo != null && existingInfo.isSystemApp()) {
+            if (fitsOnInternal) {
+                return StorageManager.UUID_PRIVATE_INTERNAL;
+            } else {
+                throw new IOException("Not enough space on existing volume "
+                        + existingInfo.volumeUuid + " for system app " + packageName + " upgrade");
+            }
         }
 
-        final StorageManager storageManager = context.getSystemService(StorageManager.class);
-        final boolean fitsOnInternal = fitsOnInternal(context, sizeBytes);
-
+        // Now deal with non-system apps.
         final ArraySet<String> allCandidates = new ArraySet<>();
         VolumeInfo bestCandidate = null;
         long bestCandidateAvailBytes = Long.MIN_VALUE;
         for (VolumeInfo vol : storageManager.getVolumes()) {
-            if (vol.type == VolumeInfo.TYPE_PRIVATE && vol.isMountedWritable()) {
+            boolean isInternalStorage = ID_PRIVATE_INTERNAL.equals(vol.id);
+            if (vol.type == VolumeInfo.TYPE_PRIVATE && vol.isMountedWritable()
+                    && (!isInternalStorage || allow3rdPartyOnInternal)) {
                 final long availBytes = storageManager.getStorageBytesUntilLow(new File(vol.path));
                 if (availBytes >= sizeBytes) {
                     allCandidates.add(vol.fsUuid);
@@ -378,11 +461,6 @@
             }
         }
 
-        // System apps always forced to internal storage
-        if (existingInfo != null && existingInfo.isSystemApp()) {
-            installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
-        }
-
         // If app expresses strong desire for internal storage, honor it
         if (!forceAllowOnExternal
                 && installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
@@ -391,6 +469,11 @@
                 throw new IOException("Cannot automatically move " + packageName + " from "
                         + existingInfo.volumeUuid + " to internal storage");
             }
+
+            if (!allow3rdPartyOnInternal) {
+                throw new IOException("Not allowed to install non-system apps on internal storage");
+            }
+
             if (fitsOnInternal) {
                 return StorageManager.UUID_PRIVATE_INTERNAL;
             } else {
@@ -411,14 +494,13 @@
             }
         }
 
-        // We're left with either preferring external or auto, so just pick
+        // We're left with new installations with either preferring external or auto, so just pick
         // volume with most space
         if (bestCandidate != null) {
             return bestCandidate.fsUuid;
-        } else if (fitsOnInternal) {
-            return StorageManager.UUID_PRIVATE_INTERNAL;
         } else {
-            throw new IOException("No special requests, but no room anywhere");
+            throw new IOException("No special requests, but no room on allowed volumes. "
+                + " allow3rdPartyOnInternal? " + allow3rdPartyOnInternal);
         }
     }
 
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index b60e6b5..99dbb1c 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -111,7 +111,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 150 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 151 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -1603,7 +1603,7 @@
         @Override
         public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
             super.writeToParcel(out, elapsedRealtimeUs);
-            out.writeLong(mMaxDurationMs);
+            out.writeLong(getMaxDurationMsLocked(elapsedRealtimeUs / 1000));
         }
 
         /**
@@ -1616,7 +1616,7 @@
         @Override
         public void writeSummaryFromParcelLocked(Parcel out, long elapsedRealtimeUs) {
             super.writeSummaryFromParcelLocked(out, elapsedRealtimeUs);
-            out.writeLong(mMaxDurationMs);
+            out.writeLong(getMaxDurationMsLocked(elapsedRealtimeUs / 1000));
         }
 
         /**
@@ -1640,7 +1640,7 @@
         public void onTimeStarted(long elapsedRealtimeUs, long baseUptime, long baseRealtime) {
             super.onTimeStarted(elapsedRealtimeUs, baseUptime, baseRealtime);
             if (mNesting > 0) {
-                mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime()*1000) / 1000;
+                mStartTimeMs = baseRealtime / 1000;
             }
         }
 
@@ -1650,10 +1650,11 @@
          * If the timer is running, add the duration into mCurrentDurationMs.
          */
         @Override
-        public void onTimeStopped(long elapsedRealtimeUs, long baseUptime, long baseRealtime) {
-            super.onTimeStopped(elapsedRealtimeUs, baseUptime, baseRealtime);
+        public void onTimeStopped(long elapsedRealtimeUs, long baseUptime, long baseRealtimeUs) {
+            super.onTimeStopped(elapsedRealtimeUs, baseUptime, baseRealtimeUs);
             if (mNesting > 0) {
-                mCurrentDurationMs += (elapsedRealtimeUs / 1000) - mStartTimeMs;
+                // baseRealtimeUs has already been converted to the timebase's realtime.
+                mCurrentDurationMs += (baseRealtimeUs / 1000) - mStartTimeMs;
             }
             mStartTimeMs = -1;
         }
@@ -1668,7 +1669,7 @@
             super.startRunningLocked(elapsedRealtimeMs);
             if (mNesting == 1 && mTimeBase.isRunning()) {
                 // Just started
-                mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime()*1000) / 1000;
+                mStartTimeMs = mTimeBase.getRealtime(elapsedRealtimeMs * 1000) / 1000;
             }
         }
 
@@ -1680,8 +1681,7 @@
          */
         @Override
         public void stopRunningLocked(long elapsedRealtimeMs) {
-            super.stopRunningLocked(elapsedRealtimeMs);
-            if (mNesting == 0) {
+            if (mNesting == 1) {
                 final long durationMs = getCurrentDurationMsLocked(elapsedRealtimeMs);
                 if (durationMs > mMaxDurationMs) {
                     mMaxDurationMs = durationMs;
@@ -1689,6 +1689,9 @@
                 mStartTimeMs = -1;
                 mCurrentDurationMs = 0;
             }
+            // super method decrements mNesting, which getCurrentDurationMsLocked relies on,
+            // so call super.stopRunningLocked after calling getCurrentDurationMsLocked.
+            super.stopRunningLocked(elapsedRealtimeMs);
         }
 
         @Override
@@ -1730,11 +1733,9 @@
         @Override
         public long getCurrentDurationMsLocked(long elapsedRealtimeMs) {
             long durationMs = mCurrentDurationMs;
-            if (mNesting > 0) {
-                if (mTimeBase.isRunning()) {
-                    durationMs += (mTimeBase.getRealtime(elapsedRealtimeMs*1000)/1000)
-                            - mStartTimeMs;
-                }
+            if (mNesting > 0 && mTimeBase.isRunning()) {
+                durationMs += (mTimeBase.getRealtime(elapsedRealtimeMs*1000)/1000)
+                        - mStartTimeMs;
             }
             return durationMs;
         }
diff --git a/core/java/com/android/internal/os/IDropBoxManagerService.aidl b/core/java/com/android/internal/os/IDropBoxManagerService.aidl
index d067926..d16579c 100644
--- a/core/java/com/android/internal/os/IDropBoxManagerService.aidl
+++ b/core/java/com/android/internal/os/IDropBoxManagerService.aidl
@@ -17,7 +17,6 @@
 package com.android.internal.os;
 
 import android.os.DropBoxManager;
-import android.os.ParcelFileDescriptor;
 
 /**
  * "Backend" interface used by {@link android.os.DropBoxManager} to talk to the
diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java
index d968e3c..a8a5549 100644
--- a/core/java/com/android/internal/os/WebViewZygoteInit.java
+++ b/core/java/com/android/internal/os/WebViewZygoteInit.java
@@ -62,6 +62,9 @@
             ClassLoader loader = ApplicationLoaders.getDefault().createAndCacheWebViewClassLoader(
                     packagePath, libsPath);
 
+            // Add the APK to the Zygote's list of allowed files for children.
+            Zygote.nativeAllowFileAcrossFork(packagePath);
+
             // Once we have the classloader, look up the WebViewFactoryProvider implementation and
             // call preloadInZygote() on it to give it the opportunity to preload the native library
             // and perform any other initialisation work that should be shared among the children.
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index fc0ccb7..293de3d 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -153,6 +153,11 @@
             int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
 
     /**
+     * Lets children of the zygote inherit open file descriptors to this path.
+     */
+    native protected static void nativeAllowFileAcrossFork(String path);
+
+    /**
      * Zygote unmount storage space on initializing.
      * This method is called once.
      */
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 7edc938..39cb464 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -695,9 +695,11 @@
             throws ZygoteSecurityException {
         int peerUid = peer.getUid();
 
-        if (args.invokeWith != null && peerUid != 0) {
-            throw new ZygoteSecurityException("Peer is not permitted to specify "
-                    + "an explicit invoke-with wrapper command");
+        if (args.invokeWith != null && peerUid != 0 &&
+            (args.debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) == 0) {
+            throw new ZygoteSecurityException("Peer is permitted to specify an"
+                    + "explicit invoke-with wrapper command only for debuggable"
+                    + "applications.");
         }
     }
 
diff --git a/core/java/com/android/internal/util/TokenBucket.java b/core/java/com/android/internal/util/TokenBucket.java
index effb82b..a163ceb 100644
--- a/core/java/com/android/internal/util/TokenBucket.java
+++ b/core/java/com/android/internal/util/TokenBucket.java
@@ -33,6 +33,8 @@
  * The available amount of tokens is computed lazily when the bucket state is inspected.
  * Therefore it is purely synchronous and does not involve any asynchronous activity.
  * It is not synchronized in any way and not a thread-safe object.
+ *
+ * {@hide}
  */
 public class TokenBucket {
 
diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java
index 83b49eb..b5d6268 100644
--- a/core/java/com/android/internal/widget/SwipeDismissLayout.java
+++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java
@@ -339,18 +339,16 @@
         mVelocityTracker.addMovement(ev);
         mVelocityTracker.computeCurrentVelocity(1000);
         if (!mDismissed) {
-
-            if (deltaX > (getWidth() * DISMISS_MIN_DRAG_WIDTH_RATIO) &&
-                    ev.getRawX() >= mLastX) {
+            if ((deltaX > (getWidth() * DISMISS_MIN_DRAG_WIDTH_RATIO) &&
+                    ev.getRawX() >= mLastX)
+                    || mVelocityTracker.getXVelocity() >= mMinFlingVelocity) {
                 mDismissed = true;
             }
         }
         // Check if the user tried to undo this.
         if (mDismissed && mSwiping) {
-            // Check if the user's finger is actually back
-            if (deltaX < (getWidth() * DISMISS_MIN_DRAG_WIDTH_RATIO) ||
-                    // or user is flinging back left
-                    mVelocityTracker.getXVelocity() < -mMinFlingVelocity) {
+            // Check if the user's finger is actually flinging back to left
+            if (mVelocityTracker.getXVelocity() < -mMinFlingVelocity) {
                 mDismissed = false;
             }
         }
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index e447dd2..3555057 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -136,7 +136,6 @@
     android/graphics/PathEffect.cpp \
     android/graphics/Picture.cpp \
     android/graphics/BitmapRegionDecoder.cpp \
-    android/graphics/Rasterizer.cpp \
     android/graphics/Region.cpp \
     android/graphics/Shader.cpp \
     android/graphics/SurfaceTexture.cpp \
@@ -189,8 +188,10 @@
     com_android_internal_util_VirtualRefBasePtr.cpp \
     com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp \
     hwbinder/EphemeralStorage.cpp \
+    fd_utils.cpp \
 
 LOCAL_C_INCLUDES += \
+    $(LOCAL_PATH)/include \
     $(JNI_H_INCLUDE) \
     $(LOCAL_PATH)/android/graphics \
     $(LOCAL_PATH)/../../libs/hwui \
@@ -284,8 +285,10 @@
 # <bionic_tls.h> in com_google_android_gles_jni_GLImpl.cpp
 LOCAL_C_INCLUDES += bionic/libc/private
 
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+
 # AndroidRuntime.h depends on nativehelper/jni.h
-LOCAL_EXPORT_C_INCLUDE_DIRS := libnativehelper/include
+LOCAL_EXPORT_C_INCLUDE_DIRS += libnativehelper/include
 
 LOCAL_MODULE:= libandroid_runtime
 
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 1f810ac..d47c6b7 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -121,13 +121,11 @@
 extern int register_android_graphics_ColorFilter(JNIEnv* env);
 extern int register_android_graphics_DrawFilter(JNIEnv* env);
 extern int register_android_graphics_FontFamily(JNIEnv* env);
-extern int register_android_graphics_LayerRasterizer(JNIEnv*);
 extern int register_android_graphics_Matrix(JNIEnv* env);
 extern int register_android_graphics_Paint(JNIEnv* env);
 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_Rasterizer(JNIEnv* env);
 extern int register_android_graphics_Region(JNIEnv* env);
 extern int register_android_graphics_SurfaceTexture(JNIEnv* env);
 extern int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env);
@@ -1332,7 +1330,6 @@
     REG_JNI(register_android_graphics_DrawFilter),
     REG_JNI(register_android_graphics_FontFamily),
     REG_JNI(register_android_graphics_Interpolator),
-    REG_JNI(register_android_graphics_LayerRasterizer),
     REG_JNI(register_android_graphics_MaskFilter),
     REG_JNI(register_android_graphics_Matrix),
     REG_JNI(register_android_graphics_Movie),
@@ -1342,7 +1339,6 @@
     REG_JNI(register_android_graphics_PathMeasure),
     REG_JNI(register_android_graphics_PathEffect),
     REG_JNI(register_android_graphics_Picture),
-    REG_JNI(register_android_graphics_Rasterizer),
     REG_JNI(register_android_graphics_Region),
     REG_JNI(register_android_graphics_Shader),
     REG_JNI(register_android_graphics_SurfaceTexture),
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 178e073..b656bb0 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -5,7 +5,11 @@
 #include "SkPixelRef.h"
 #include "SkImageEncoder.h"
 #include "SkImageInfo.h"
+#include "SkColor.h"
 #include "SkColorPriv.h"
+#include "SkHalf.h"
+#include "SkPM4f.h"
+#include "SkPM4fPriv.h"
 #include "GraphicsJNI.h"
 #include "SkDither.h"
 #include "SkUnPreMultiply.h"
@@ -232,6 +236,28 @@
 typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,
                               int x, int y);
 
+static void FromColor_F16(void* dst, const SkColor src[], int width,
+                          int, int) {
+    uint64_t* d = (uint64_t*)dst;
+
+    for (int i = 0; i < width; i++) {
+        *d++ = SkColor4f::FromColor(*src++).premul().toF16();
+    }
+}
+
+static void FromColor_F16_Raw(void* dst, const SkColor src[], int width,
+                          int, int) {
+    uint64_t* d = (uint64_t*)dst;
+
+    for (int i = 0; i < width; i++) {
+        const float* color = SkColor4f::FromColor(*src++).vec();
+        uint16_t* scratch = reinterpret_cast<uint16_t*>(d++);
+        for (int i = 0; i < 4; ++i) {
+            scratch[i] = SkFloatToHalf(color[i]);
+        }
+    }
+}
+
 static void FromColor_D32(void* dst, const SkColor src[], int width,
                           int, int) {
     SkPMColor* d = (SkPMColor*)dst;
@@ -321,6 +347,8 @@
             return FromColor_D565;
         case kAlpha_8_SkColorType:
             return FromColor_DA8;
+        case kRGBA_F16_SkColorType:
+            return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_F16 : FromColor_F16_Raw;
         default:
             break;
     }
@@ -351,8 +379,7 @@
 
     dstBitmap.notifyPixelsChanged();
 
-    env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array),
-                                 JNI_ABORT);
+    env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array), JNI_ABORT);
     return true;
 }
 
@@ -361,6 +388,24 @@
 typedef void (*ToColorProc)(SkColor dst[], const void* src, int width,
                             SkColorTable*);
 
+static void ToColor_F16_Alpha(SkColor dst[], const void* src, int width,
+                              SkColorTable*) {
+    SkASSERT(width > 0);
+    uint64_t* s = (uint64_t*)src;
+    do {
+        *dst++ = SkPM4f::FromF16((const uint16_t*) s++).unpremul().toSkColor();
+    } while (--width != 0);
+}
+
+static void ToColor_F16_Raw(SkColor dst[], const void* src, int width,
+                            SkColorTable*) {
+    SkASSERT(width > 0);
+    uint64_t* s = (uint64_t*)src;
+    do {
+        *dst++ = Sk4f_toS32(swizzle_rb(SkHalfToFloat_finite_ftz(*s++)));
+    } while (--width != 0);
+}
+
 static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width,
                               SkColorTable*) {
     SkASSERT(width > 0);
@@ -520,6 +565,17 @@
             }
         case kAlpha_8_SkColorType:
             return ToColor_SA8;
+        case kRGBA_F16_SkColorType:
+            switch (src.alphaType()) {
+                case kOpaque_SkAlphaType:
+                    return ToColor_F16_Raw;
+                case kPremul_SkAlphaType:
+                    return ToColor_F16_Alpha;
+                case kUnpremul_SkAlphaType:
+                    return ToColor_F16_Raw;
+                default:
+                    return NULL;
+            }
         default:
             break;
     }
@@ -554,7 +610,7 @@
 
     SkBitmap bitmap;
     bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType,
-            GraphicsJNI::defaultColorSpace()));
+            GraphicsJNI::colorSpaceForType(colorType)));
 
     sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(&bitmap, NULL);
     if (!nativeBitmap) {
@@ -562,8 +618,7 @@
     }
 
     if (jColors != NULL) {
-        GraphicsJNI::SetPixels(env, jColors, offset, stride,
-                0, 0, width, height, bitmap);
+        GraphicsJNI::SetPixels(env, jColors, offset, stride, 0, 0, width, height, bitmap);
     }
 
     return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable));
@@ -712,6 +767,9 @@
 
 static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {
     LocalScopedBitmap bitmap(bitmapHandle);
+    if (bitmap->bitmap().isHardware()) {
+        return GraphicsJNI::hardwareLegacyBitmapConfig();
+    }
     return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->info().colorType());
 }
 
@@ -787,6 +845,7 @@
     const int         density = p->readInt32();
 
     if (kN32_SkColorType != colorType &&
+            kRGBA_F16_SkColorType != colorType &&
             kRGB_565_SkColorType != colorType &&
             kARGB_4444_SkColorType != colorType &&
             kIndex_8_SkColorType != colorType &&
@@ -797,8 +856,15 @@
 
     std::unique_ptr<SkBitmap> bitmap(new SkBitmap);
 
-    if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType,
-            isSRGB ? SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named) : nullptr), rowBytes)) {
+    sk_sp<SkColorSpace> colorSpace;
+    if (kRGBA_F16_SkColorType == colorType) {
+        colorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGBLinear_Named);
+    } else {
+        colorSpace = isSRGB ? SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named) : nullptr;
+    }
+
+    if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType, colorSpace),
+            rowBytes)) {
         return NULL;
     }
 
@@ -1128,8 +1194,19 @@
                               jlong bm1Handle) {
     SkBitmap bm0;
     SkBitmap bm1;
-    reinterpret_cast<BitmapWrapper*>(bm0Handle)->getSkBitmap(&bm0);
-    reinterpret_cast<BitmapWrapper*>(bm1Handle)->getSkBitmap(&bm1);
+
+    LocalScopedBitmap bitmap0(bm0Handle);
+    LocalScopedBitmap bitmap1(bm1Handle);
+
+    // Paying the price for making Hardware Bitmap as Config:
+    // later check for colorType will pass successfully,
+    // because Hardware Config internally may be RGBA8888 or smth like that.
+    if (bitmap0->bitmap().isHardware() != bitmap1->bitmap().isHardware()) {
+        return JNI_FALSE;
+    }
+
+    bitmap0->bitmap().getSkBitmap(&bm0);
+    bitmap1->bitmap().getSkBitmap(&bm1);
     if (bm0.width() != bm1.width() ||
         bm0.height() != bm1.height() ||
         bm0.colorType() != bm1.colorType() ||
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index e86acc4..69c7054 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -276,10 +276,15 @@
         }
     }
 
+    if (isMutable && isHardware) {
+        doThrowIAE(env, "Bitmaps with Config.HARWARE are always immutable");
+        return nullObjectReturn("Cannot create mutable hardware bitmap");
+    }
+
     // Create the codec.
     NinePatchPeeker peeker;
-    std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(streamDeleter.release(),
-            &peeker));
+    std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(
+            streamDeleter.release(), &peeker));
     if (!codec.get()) {
         return nullObjectReturn("SkAndroidCodec::NewFromStream returned null");
     }
@@ -390,9 +395,12 @@
     SkAlphaType alphaType = codec->computeOutputAlphaType(requireUnpremultiplied);
 
     const SkImageInfo decodeInfo = SkImageInfo::Make(size.width(), size.height(),
-            decodeColorType, alphaType, GraphicsJNI::defaultColorSpace());
+            decodeColorType, alphaType, codec->computeOutputColorSpace(decodeColorType));
 
-    SkImageInfo bitmapInfo = decodeInfo;
+    // We always decode to sRGB, but only mark the bitmap with a color space if linear
+    // blending is enabled.
+    SkImageInfo bitmapInfo = decodeInfo.makeColorSpace(
+            GraphicsJNI::colorSpaceForType(decodeColorType));
     if (decodeColorType == kGray_8_SkColorType) {
         // The legacy implementation of BitmapFactory used kAlpha8 for
         // grayscale images (before kGray8 existed).  While the codec
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index e740428..6f97c60 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -297,13 +297,16 @@
     kRGB_565_LegacyBitmapConfig     = 3,
     kARGB_4444_LegacyBitmapConfig   = 4,
     kARGB_8888_LegacyBitmapConfig   = 5,
-    kHardware_LegacyBitmapConfig    = 6,
+    kRGBA_16F_LegacyBitmapConfig    = 6,
+    kHardware_LegacyBitmapConfig    = 7,
 
     kLastEnum_LegacyBitmapConfig = kHardware_LegacyBitmapConfig
 };
 
 jint GraphicsJNI::colorTypeToLegacyBitmapConfig(SkColorType colorType) {
     switch (colorType) {
+        case kRGBA_F16_SkColorType:
+            return kRGBA_16F_LegacyBitmapConfig;
         case kN32_SkColorType:
             return kARGB_8888_LegacyBitmapConfig;
         case kARGB_4444_SkColorType:
@@ -329,6 +332,7 @@
         kRGB_565_SkColorType,
         kARGB_4444_SkColorType,
         kN32_SkColorType,
+        kRGBA_F16_SkColorType,
         kN32_SkColorType
     };
 
@@ -366,6 +370,10 @@
     return c == kHardware_LegacyBitmapConfig;
 }
 
+jint GraphicsJNI::hardwareLegacyBitmapConfig() {
+    return kHardware_LegacyBitmapConfig;
+}
+
 android::Canvas* GraphicsJNI::getNativeCanvas(JNIEnv* env, jobject canvas) {
     SkASSERT(env);
     SkASSERT(canvas);
@@ -454,6 +462,19 @@
 #endif
 }
 
+sk_sp<SkColorSpace> GraphicsJNI::linearColorSpace() {
+    return SkColorSpace::MakeNamed(SkColorSpace::kSRGBLinear_Named);
+}
+
+sk_sp<SkColorSpace> GraphicsJNI::colorSpaceForType(SkColorType type) {
+    switch (type) {
+        case kRGBA_F16_SkColorType:
+            return linearColorSpace();
+        default:
+            return defaultColorSpace();
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 bool HeapAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
     mStorage = android::Bitmap::allocateHeapBitmap(bitmap, ctable);
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index ced9939..508c9ff 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -69,6 +69,7 @@
     static SkColorType getNativeBitmapColorType(JNIEnv*, jobject jconfig);
 
     static bool isHardwareConfig(JNIEnv* env, jobject jconfig);
+    static jint hardwareLegacyBitmapConfig();
 
     static jobject createRegion(JNIEnv* env, SkRegion* region);
 
@@ -94,6 +95,8 @@
             const SkBitmap& dstBitmap);
 
     static sk_sp<SkColorSpace> defaultColorSpace();
+    static sk_sp<SkColorSpace> linearColorSpace();
+    static sk_sp<SkColorSpace> colorSpaceForType(SkColorType type);
 };
 
 class HeapAllocator : public SkBRDAllocator {
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 3456839..dfe809d 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -30,7 +30,6 @@
 #include "SkMaskFilter.h"
 #include "SkPath.h"
 #include "SkPathEffect.h"
-#include "SkRasterizer.h"
 #include "SkShader.h"
 #include "SkBlendMode.h"
 #include "unicode/uloc.h"
@@ -848,12 +847,6 @@
         return 0;
     }
 
-    static jlong setRasterizer(jlong objHandle, jlong rasterizerHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        obj->setRasterizer(GraphicsJNI::refNativeRasterizer(rasterizerHandle));
-        return reinterpret_cast<jlong>(obj->getRasterizer());
-    }
-
     static jint getTextAlign(jlong objHandle) {
         Paint* obj = reinterpret_cast<Paint*>(objHandle);
         return static_cast<jint>(obj->getTextAlign());
@@ -1038,7 +1031,6 @@
     {"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",
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index ab393f2..292454b 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -36,7 +36,18 @@
 class SkPathGlue {
 public:
 
-    static void finalizer(JNIEnv* env, jobject clazz, jlong objHandle) {
+    // ---------------- Regular JNI -----------------------------
+
+    static jlong init(JNIEnv* env, jclass clazz) {
+        return reinterpret_cast<jlong>(new SkPath());
+    }
+
+    static jlong init_Path(JNIEnv* env, jclass clazz, jlong valHandle) {
+        SkPath* val = reinterpret_cast<SkPath*>(valHandle);
+        return reinterpret_cast<jlong>(new SkPath(*val));
+    }
+
+    static void finalize(JNIEnv* env, jclass clazz, jlong objHandle) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         // Purge entries from the HWUI path cache if this path's data is unique
         if (obj->unique() && android::uirenderer::Caches::hasInstance()) {
@@ -45,112 +56,68 @@
         delete obj;
     }
 
-    static jlong init1(JNIEnv* env, jobject clazz) {
-        return reinterpret_cast<jlong>(new SkPath());
-    }
-
-    static jlong init2(JNIEnv* env, jobject clazz, jlong valHandle) {
-        SkPath* val = reinterpret_cast<SkPath*>(valHandle);
-        return reinterpret_cast<jlong>(new SkPath(*val));
-    }
-
-    static void reset(JNIEnv* env, jobject clazz, jlong objHandle) {
-        SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
-        obj->reset();
-    }
-
-    static void rewind(JNIEnv* env, jobject clazz, jlong objHandle) {
-        SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
-        obj->rewind();
-    }
-
-    static void assign(JNIEnv* env, jobject clazz, jlong dstHandle, jlong srcHandle) {
+    static void set(JNIEnv* env, jclass clazz, jlong dstHandle, jlong srcHandle) {
         SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
         const SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
         *dst = *src;
     }
 
-    static jboolean isConvex(JNIEnv* env, jobject clazz, jlong objHandle) {
-        SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
-        return obj->isConvex();
-    }
-
-    static jint getFillType(JNIEnv* env, jobject clazz, jlong objHandle) {
-        SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
-        return obj->getFillType();
-    }
-
-    static void setFillType(JNIEnv* env, jobject clazz, jlong pathHandle, jint ftHandle) {
-        SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
-        SkPath::FillType ft = static_cast<SkPath::FillType>(ftHandle);
-        path->setFillType(ft);
-    }
-
-    static jboolean isEmpty(JNIEnv* env, jobject clazz, jlong objHandle) {
-        SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
-        return obj->isEmpty();
-    }
-
-    static jboolean isRect(JNIEnv* env, jobject clazz, jlong objHandle, jobject jrect) {
-        SkRect rect;
-        SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
-        jboolean result = obj->isRect(&rect);
-        GraphicsJNI::rect_to_jrectf(rect, env, jrect);
-        return result;
-    }
-
-    static void computeBounds(JNIEnv* env, jobject clazz, jlong objHandle, jobject jbounds) {
+    static void computeBounds(JNIEnv* env, jclass clazz, jlong objHandle, jobject jbounds) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         const SkRect& bounds = obj->getBounds();
         GraphicsJNI::rect_to_jrectf(bounds, env, jbounds);
     }
 
-    static void incReserve(JNIEnv* env, jobject clazz, jlong objHandle, jint extraPtCount) {
+    static void incReserve(JNIEnv* env, jclass clazz, jlong objHandle, jint extraPtCount) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->incReserve(extraPtCount);
     }
 
-    static void moveTo__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x, jfloat y) {
+    static void moveTo__FF(JNIEnv* env, jclass clazz, jlong objHandle, jfloat x, jfloat y) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->moveTo(x, y);
     }
 
-    static void rMoveTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) {
+    static void rMoveTo(JNIEnv* env, jclass clazz, jlong objHandle, jfloat dx, jfloat dy) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->rMoveTo(dx, dy);
     }
 
-    static void lineTo__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x, jfloat y) {
+    static void lineTo__FF(JNIEnv* env, jclass clazz, jlong objHandle, jfloat x, jfloat y) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->lineTo(x, y);
     }
 
-    static void rLineTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) {
+    static void rLineTo(JNIEnv* env, jclass clazz, jlong objHandle, jfloat dx, jfloat dy) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->rLineTo(dx, dy);
     }
 
-    static void quadTo__FFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x1, jfloat y1, jfloat x2, jfloat y2) {
+    static void quadTo__FFFF(JNIEnv* env, jclass clazz, jlong objHandle, jfloat x1, jfloat y1,
+            jfloat x2, jfloat y2) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->quadTo(x1, y1, x2, y2);
     }
 
-    static void rQuadTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx1, jfloat dy1, jfloat dx2, jfloat dy2) {
+    static void rQuadTo(JNIEnv* env, jclass clazz, jlong objHandle, jfloat dx1, jfloat dy1,
+            jfloat dx2, jfloat dy2) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->rQuadTo(dx1, dy1, dx2, dy2);
     }
 
-    static void cubicTo__FFFFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x1, jfloat y1, jfloat x2, jfloat y2, jfloat x3, jfloat y3) {
+    static void cubicTo__FFFFFF(JNIEnv* env, jclass clazz, jlong objHandle, jfloat x1, jfloat y1,
+            jfloat x2, jfloat y2, jfloat x3, jfloat y3) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->cubicTo(x1, y1, x2, y2, x3, y3);
     }
 
-    static void rCubicTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x1, jfloat y1, jfloat x2, jfloat y2, jfloat x3, jfloat y3) {
+    static void rCubicTo(JNIEnv* env, jclass clazz, jlong objHandle, jfloat x1, jfloat y1,
+            jfloat x2, jfloat y2, jfloat x3, jfloat y3) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->rCubicTo(x1, y1, x2, y2, x3, y3);
     }
 
-    static void arcTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat left, jfloat top,
+    static void arcTo(JNIEnv* env, jclass clazz, jlong objHandle, jfloat left, jfloat top,
             jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle,
             jboolean forceMoveTo) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
@@ -158,19 +125,19 @@
         obj->arcTo(oval, startAngle, sweepAngle, forceMoveTo);
     }
 
-    static void close(JNIEnv* env, jobject clazz, jlong objHandle) {
+    static void close(JNIEnv* env, jclass clazz, jlong objHandle) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->close();
     }
 
-    static void addRect(JNIEnv* env, jobject clazz, jlong objHandle,
+    static void addRect(JNIEnv* env, jclass clazz, jlong objHandle,
             jfloat left, jfloat top, jfloat right, jfloat bottom, jint dirHandle) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle);
         obj->addRect(left, top, right, bottom, dir);
     }
 
-    static void addOval(JNIEnv* env, jobject clazz, jlong objHandle,
+    static void addOval(JNIEnv* env, jclass clazz, jlong objHandle,
             jfloat left, jfloat top, jfloat right, jfloat bottom, jint dirHandle) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle);
@@ -178,20 +145,21 @@
         obj->addOval(oval, dir);
     }
 
-    static void addCircle(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x, jfloat y, jfloat radius, jint dirHandle) {
+    static void addCircle(JNIEnv* env, jclass clazz, jlong objHandle, jfloat x, jfloat y,
+            jfloat radius, jint dirHandle) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle);
         obj->addCircle(x, y, radius, dir);
     }
 
-    static void addArc(JNIEnv* env, jobject clazz, jlong objHandle, jfloat left, jfloat top,
+    static void addArc(JNIEnv* env, jclass clazz, jlong objHandle, jfloat left, jfloat top,
             jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle) {
         SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->addArc(oval, startAngle, sweepAngle);
     }
 
-    static void addRoundRectXY(JNIEnv* env, jobject clazz, jlong objHandle, jfloat left, jfloat top,
+    static void addRoundRectXY(JNIEnv* env, jclass clazz, jlong objHandle, jfloat left, jfloat top,
             jfloat right, jfloat bottom, jfloat rx, jfloat ry, jint dirHandle) {
         SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
@@ -199,8 +167,8 @@
         obj->addRoundRect(rect, rx, ry, dir);
     }
 
-    static void addRoundRect8(JNIEnv* env, jobject, jlong objHandle, jfloat left, jfloat top,
-            jfloat right, jfloat bottom, jfloatArray array, jint dirHandle) {
+    static void addRoundRect8(JNIEnv* env, jclass clazz, jlong objHandle, jfloat left, jfloat top,
+                jfloat right, jfloat bottom, jfloatArray array, jint dirHandle) {
         SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle);
@@ -213,49 +181,53 @@
         obj->addRoundRect(rect, src, dir);
     }
 
-    static void addPath__PathFF(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle, jfloat dx, jfloat dy) {
+    static void addPath__PathFF(JNIEnv* env, jclass clazz, jlong objHandle, jlong srcHandle,
+            jfloat dx, jfloat dy) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
         obj->addPath(*src, dx, dy);
     }
 
-    static void addPath__Path(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle) {
+    static void addPath__Path(JNIEnv* env, jclass clazz, jlong objHandle, jlong srcHandle) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
         obj->addPath(*src);
     }
 
-    static void addPath__PathMatrix(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle, jlong matrixHandle) {
+    static void addPath__PathMatrix(JNIEnv* env, jclass clazz, jlong objHandle, jlong srcHandle,
+            jlong matrixHandle) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
         SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
         obj->addPath(*src, *matrix);
     }
 
-    static void offset__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) {
+    static void offset__FF(JNIEnv* env, jclass clazz, jlong objHandle, jfloat dx, jfloat dy) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->offset(dx, dy);
     }
 
-    static void setLastPoint(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) {
+    static void setLastPoint(JNIEnv* env, jclass clazz, jlong objHandle, jfloat dx, jfloat dy) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->setLastPt(dx, dy);
     }
 
-    static void transform__MatrixPath(JNIEnv* env, jobject clazz, jlong objHandle, jlong matrixHandle, jlong dstHandle) {
+    static void transform__MatrixPath(JNIEnv* env, jclass clazz, jlong objHandle, jlong matrixHandle,
+            jlong dstHandle) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
         SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
         obj->transform(*matrix, dst);
     }
 
-    static void transform__Matrix(JNIEnv* env, jobject clazz, jlong objHandle, jlong matrixHandle) {
+    static void transform__Matrix(JNIEnv* env, jclass clazz, jlong objHandle, jlong matrixHandle) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
         obj->transform(*matrix);
     }
 
-    static jboolean op(JNIEnv* env, jobject clazz, jlong p1Handle, jlong p2Handle, jint opHandle, jlong rHandle) {
+    static jboolean op(JNIEnv* env, jclass clazz, jlong p1Handle, jlong p2Handle, jint opHandle,
+            jlong rHandle) {
         SkPath* p1  = reinterpret_cast<SkPath*>(p1Handle);
         SkPath* p2  = reinterpret_cast<SkPath*>(p2Handle);
         SkPathOp op = static_cast<SkPathOp>(opHandle);
@@ -416,8 +388,8 @@
     // Note that more than one point may have the same length along the path in
     // the case of a move.
     // NULL can be returned if the Path is empty.
-    static jfloatArray approximate(JNIEnv* env, jclass, jlong pathHandle, float acceptableError)
-    {
+    static jfloatArray approximate(JNIEnv* env, jclass clazz, jlong pathHandle,
+            float acceptableError) {
         SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
         SkASSERT(path);
         SkPath::Iter pathIter(*path, false);
@@ -467,47 +439,94 @@
         delete[] approximation;
         return result;
     }
+
+    // ---------------- @FastNative -----------------------------
+
+    static jboolean isRect(JNIEnv* env, jclass clazz, jlong objHandle, jobject jrect) {
+        SkRect rect;
+        SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
+        jboolean result = obj->isRect(&rect);
+        GraphicsJNI::rect_to_jrectf(rect, env, jrect);
+        return result;
+    }
+
+    // ---------------- @CriticalNative -------------------------
+
+    static void reset(jlong objHandle) {
+        SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
+        obj->reset();
+    }
+
+    static void rewind(jlong objHandle) {
+        SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
+        obj->rewind();
+    }
+
+    static jboolean isEmpty(jlong objHandle) {
+        SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
+        return obj->isEmpty();
+    }
+
+    static jboolean isConvex(jlong objHandle) {
+        SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
+        return obj->isConvex();
+    }
+
+    static jint getFillType(jlong objHandle) {
+        SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
+        return obj->getFillType();
+    }
+
+    static void setFillType(jlong pathHandle, jint ftHandle) {;
+        SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
+        SkPath::FillType ft = static_cast<SkPath::FillType>(ftHandle);
+        path->setFillType(ft);
+    }
 };
 
 static const JNINativeMethod methods[] = {
-    {"finalizer", "(J)V", (void*) SkPathGlue::finalizer},
-    {"init1","()J", (void*) SkPathGlue::init1},
-    {"init2","(J)J", (void*) SkPathGlue::init2},
-    {"native_reset","(J)V", (void*) SkPathGlue::reset},
-    {"native_rewind","(J)V", (void*) SkPathGlue::rewind},
-    {"native_set","(JJ)V", (void*) SkPathGlue::assign},
-    {"native_isConvex","(J)Z", (void*) SkPathGlue::isConvex},
-    {"native_getFillType","(J)I", (void*) SkPathGlue::getFillType},
-    {"native_setFillType","(JI)V", (void*) SkPathGlue::setFillType},
-    {"native_isEmpty","(J)Z", (void*) SkPathGlue::isEmpty},
-    {"native_isRect","(JLandroid/graphics/RectF;)Z", (void*) SkPathGlue::isRect},
-    {"native_computeBounds","(JLandroid/graphics/RectF;)V", (void*) SkPathGlue::computeBounds},
-    {"native_incReserve","(JI)V", (void*) SkPathGlue::incReserve},
-    {"native_moveTo","(JFF)V", (void*) SkPathGlue::moveTo__FF},
-    {"native_rMoveTo","(JFF)V", (void*) SkPathGlue::rMoveTo},
-    {"native_lineTo","(JFF)V", (void*) SkPathGlue::lineTo__FF},
-    {"native_rLineTo","(JFF)V", (void*) SkPathGlue::rLineTo},
-    {"native_quadTo","(JFFFF)V", (void*) SkPathGlue::quadTo__FFFF},
-    {"native_rQuadTo","(JFFFF)V", (void*) SkPathGlue::rQuadTo},
-    {"native_cubicTo","(JFFFFFF)V", (void*) SkPathGlue::cubicTo__FFFFFF},
-    {"native_rCubicTo","(JFFFFFF)V", (void*) SkPathGlue::rCubicTo},
-    {"native_arcTo","(JFFFFFFZ)V", (void*) SkPathGlue::arcTo},
-    {"native_close","(J)V", (void*) SkPathGlue::close},
-    {"native_addRect","(JFFFFI)V", (void*) SkPathGlue::addRect},
-    {"native_addOval","(JFFFFI)V", (void*) SkPathGlue::addOval},
-    {"native_addCircle","(JFFFI)V", (void*) SkPathGlue::addCircle},
-    {"native_addArc","(JFFFFFF)V", (void*) SkPathGlue::addArc},
-    {"native_addRoundRect","(JFFFFFFI)V", (void*) SkPathGlue::addRoundRectXY},
-    {"native_addRoundRect","(JFFFF[FI)V", (void*) SkPathGlue::addRoundRect8},
-    {"native_addPath","(JJFF)V", (void*) SkPathGlue::addPath__PathFF},
-    {"native_addPath","(JJ)V", (void*) SkPathGlue::addPath__Path},
-    {"native_addPath","(JJJ)V", (void*) SkPathGlue::addPath__PathMatrix},
-    {"native_offset","(JFF)V", (void*) SkPathGlue::offset__FF},
-    {"native_setLastPoint","(JFF)V", (void*) SkPathGlue::setLastPoint},
-    {"native_transform","(JJJ)V", (void*) SkPathGlue::transform__MatrixPath},
-    {"native_transform","(JJ)V", (void*) SkPathGlue::transform__Matrix},
-    {"native_op","(JJIJ)Z", (void*) SkPathGlue::op},
-    {"native_approximate", "(JF)[F", (void*) SkPathGlue::approximate},
+    {"nInit","()J", (void*) SkPathGlue::init},
+    {"nInit","(J)J", (void*) SkPathGlue::init_Path},
+    {"nFinalize", "(J)V", (void*) SkPathGlue::finalize},
+    {"nSet","(JJ)V", (void*) SkPathGlue::set},
+    {"nComputeBounds","(JLandroid/graphics/RectF;)V", (void*) SkPathGlue::computeBounds},
+    {"nIncReserve","(JI)V", (void*) SkPathGlue::incReserve},
+    {"nMoveTo","(JFF)V", (void*) SkPathGlue::moveTo__FF},
+    {"nRMoveTo","(JFF)V", (void*) SkPathGlue::rMoveTo},
+    {"nLineTo","(JFF)V", (void*) SkPathGlue::lineTo__FF},
+    {"nRLineTo","(JFF)V", (void*) SkPathGlue::rLineTo},
+    {"nQuadTo","(JFFFF)V", (void*) SkPathGlue::quadTo__FFFF},
+    {"nRQuadTo","(JFFFF)V", (void*) SkPathGlue::rQuadTo},
+    {"nCubicTo","(JFFFFFF)V", (void*) SkPathGlue::cubicTo__FFFFFF},
+    {"nRCubicTo","(JFFFFFF)V", (void*) SkPathGlue::rCubicTo},
+    {"nArcTo","(JFFFFFFZ)V", (void*) SkPathGlue::arcTo},
+    {"nClose","(J)V", (void*) SkPathGlue::close},
+    {"nAddRect","(JFFFFI)V", (void*) SkPathGlue::addRect},
+    {"nAddOval","(JFFFFI)V", (void*) SkPathGlue::addOval},
+    {"nAddCircle","(JFFFI)V", (void*) SkPathGlue::addCircle},
+    {"nAddArc","(JFFFFFF)V", (void*) SkPathGlue::addArc},
+    {"nAddRoundRect","(JFFFFFFI)V", (void*) SkPathGlue::addRoundRectXY},
+    {"nAddRoundRect","(JFFFF[FI)V", (void*) SkPathGlue::addRoundRect8},
+    {"nAddPath","(JJFF)V", (void*) SkPathGlue::addPath__PathFF},
+    {"nAddPath","(JJ)V", (void*) SkPathGlue::addPath__Path},
+    {"nAddPath","(JJJ)V", (void*) SkPathGlue::addPath__PathMatrix},
+    {"nOffset","(JFF)V", (void*) SkPathGlue::offset__FF},
+    {"nSetLastPoint","(JFF)V", (void*) SkPathGlue::setLastPoint},
+    {"nTransform","(JJJ)V", (void*) SkPathGlue::transform__MatrixPath},
+    {"nTransform","(JJ)V", (void*) SkPathGlue::transform__Matrix},
+    {"nOp","(JJIJ)Z", (void*) SkPathGlue::op},
+    {"nApproximate", "(JF)[F", (void*) SkPathGlue::approximate},
+
+    // ------- @FastNative below here ----------------------
+    {"nIsRect","(JLandroid/graphics/RectF;)Z", (void*) SkPathGlue::isRect},
+
+    // ------- @CriticalNative below here ------------------
+    {"nReset","(J)V", (void*) SkPathGlue::reset},
+    {"nRewind","(J)V", (void*) SkPathGlue::rewind},
+    {"nIsEmpty","(J)Z", (void*) SkPathGlue::isEmpty},
+    {"nIsConvex","(J)Z", (void*) SkPathGlue::isConvex},
+    {"nGetFillType","(J)I", (void*) SkPathGlue::getFillType},
+    {"nSetFillType","(JI)V", (void*) SkPathGlue::setFillType},
 };
 
 int register_android_graphics_Path(JNIEnv* env) {
diff --git a/core/jni/android/graphics/Rasterizer.cpp b/core/jni/android/graphics/Rasterizer.cpp
deleted file mode 100644
index f409498..0000000
--- a/core/jni/android/graphics/Rasterizer.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/* libs/android_runtime/android/graphics/Rasterizer.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: SkRasterizer.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 "SkLayerRasterizer.h"
-#include "core_jni_helpers.h"
-
-#include <hwui/Paint.h>
-
-// Rasterizer.java holds a pointer (jlong) to this guy
-class NativeRasterizer {
-public:
-    NativeRasterizer() {}
-    virtual ~NativeRasterizer() {}
-
-    // Can return NULL, or a ref to the skia rasterizer.
-    virtual sk_sp<SkRasterizer> refRasterizer() { return NULL; }
-};
-
-class NativeLayerRasterizer : public NativeRasterizer {
-public:
-    SkLayerRasterizer::Builder fBuilder;
-
-    virtual sk_sp<SkRasterizer> refRasterizer() {
-        return fBuilder.snapshot();
-    }
-};
-
-sk_sp<SkRasterizer> GraphicsJNI::refNativeRasterizer(jlong rasterizerHandle) {
-    NativeRasterizer* nr = reinterpret_cast<NativeRasterizer*>(rasterizerHandle);
-    return nr ? nr->refRasterizer() : NULL;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-namespace android {
-
-class SkRasterizerGlue {
-public:
-    static void finalizer(JNIEnv* env, jobject clazz, jlong objHandle) {
-        delete reinterpret_cast<NativeRasterizer *>(objHandle);
-    }
-};
-
-static const JNINativeMethod gRasterizerMethods[] = {
-    {"finalizer", "(J)V", (void*) SkRasterizerGlue::finalizer}
-};
-
-int register_android_graphics_Rasterizer(JNIEnv* env) {
-    return RegisterMethodsOrDie(env, "android/graphics/Rasterizer", gRasterizerMethods,
-                                NELEM(gRasterizerMethods));
-}
-
-class SkLayerRasterizerGlue {
-public:
-    static jlong create(JNIEnv* env, jobject) {
-        return reinterpret_cast<jlong>(new NativeLayerRasterizer);
-    }
-
-    static void addLayer(JNIEnv* env, jobject, jlong layerHandle, jlong paintHandle, jfloat dx, jfloat dy) {
-        NativeLayerRasterizer* nr = reinterpret_cast<NativeLayerRasterizer *>(layerHandle);
-        const Paint* paint = reinterpret_cast<Paint *>(paintHandle);
-        SkASSERT(nr);
-        SkASSERT(paint);
-        nr->fBuilder.addLayer(*paint, dx, dy);
-    }
-};
-
-static const JNINativeMethod gLayerRasterizerMethods[] = {
-    { "nativeConstructor",  "()J",      (void*)SkLayerRasterizerGlue::create    },
-    { "nativeAddLayer",     "(JJFF)V",  (void*)SkLayerRasterizerGlue::addLayer  }
-};
-
-int register_android_graphics_LayerRasterizer(JNIEnv* env)
-{
-    return RegisterMethodsOrDie(env, "android/graphics/LayerRasterizer",
-                                gLayerRasterizerMethods, NELEM(gLayerRasterizerMethods));
-}
-
-}
-
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index a31bd80..be9449b 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -185,12 +185,12 @@
 
 // SkRegion::Op and SkClipOp are numerically identical, so we can freely cast
 // from one to the other (though SkClipOp is destined to become a strict subset)
-static_assert(SkRegion::kDifference_Op == static_cast<SkRegion::Op>(kDifference_SkClipOp), "");
-static_assert(SkRegion::kIntersect_Op == static_cast<SkRegion::Op>(kIntersect_SkClipOp), "");
-static_assert(SkRegion::kUnion_Op == static_cast<SkRegion::Op>(kUnion_SkClipOp), "");
-static_assert(SkRegion::kXOR_Op == static_cast<SkRegion::Op>(kXOR_SkClipOp), "");
-static_assert(SkRegion::kReverseDifference_Op == static_cast<SkRegion::Op>(kReverseDifference_SkClipOp), "");
-static_assert(SkRegion::kReplace_Op == static_cast<SkRegion::Op>(kReplace_SkClipOp), "");
+static_assert(SkRegion::kDifference_Op == static_cast<SkRegion::Op>(SkClipOp::kDifference), "");
+static_assert(SkRegion::kIntersect_Op == static_cast<SkRegion::Op>(SkClipOp::kIntersect), "");
+static_assert(SkRegion::kUnion_Op == static_cast<SkRegion::Op>(SkClipOp::kUnion), "");
+static_assert(SkRegion::kXOR_Op == static_cast<SkRegion::Op>(SkClipOp::kXOR), "");
+static_assert(SkRegion::kReverseDifference_Op == static_cast<SkRegion::Op>(SkClipOp::kReverseDifference), "");
+static_assert(SkRegion::kReplace_Op == static_cast<SkRegion::Op>(SkClipOp::kReplace), "");
 
 static SkClipOp opHandleToClipOp(jint opHandle) {
     // The opHandle is defined in Canvas.java to be Region::Op
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 26a2cf0..3e99521 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -44,28 +44,33 @@
 
 namespace android {
 
+static const uint32_t kEtherTypeOffset = offsetof(ether_header, ether_type);
+static const uint32_t kEtherHeaderLen = sizeof(ether_header);
+static const uint32_t kIPv4Protocol = kEtherHeaderLen + offsetof(iphdr, protocol);
+static const uint32_t kIPv4FlagsOffset = kEtherHeaderLen + offsetof(iphdr, frag_off);
+static const uint32_t kIPv6NextHeader = kEtherHeaderLen + offsetof(ip6_hdr, ip6_nxt);
+static const uint32_t kIPv6PayloadStart = kEtherHeaderLen + sizeof(ip6_hdr);
+static const uint32_t kICMPv6TypeOffset = kIPv6PayloadStart + offsetof(icmp6_hdr, icmp6_type);
+static const uint32_t kUDPSrcPortIndirectOffset = kEtherHeaderLen + offsetof(udphdr, source);
+static const uint32_t kUDPDstPortIndirectOffset = kEtherHeaderLen + offsetof(udphdr, dest);
 static const uint16_t kDhcpClientPort = 68;
 
 static void android_net_utils_attachDhcpFilter(JNIEnv *env, jobject clazz, jobject javaFd)
 {
-    uint32_t ip_offset = sizeof(ether_header);
-    uint32_t proto_offset = ip_offset + offsetof(iphdr, protocol);
-    uint32_t flags_offset = ip_offset + offsetof(iphdr, frag_off);
-    uint32_t dport_indirect_offset = ip_offset + offsetof(udphdr, dest);
     struct sock_filter filter_code[] = {
         // Check the protocol is UDP.
-        BPF_STMT(BPF_LD  | BPF_B   | BPF_ABS,  proto_offset),
+        BPF_STMT(BPF_LD  | BPF_B   | BPF_ABS,  kIPv4Protocol),
         BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K,    IPPROTO_UDP, 0, 6),
 
         // Check this is not a fragment.
-        BPF_STMT(BPF_LD  | BPF_H    | BPF_ABS, flags_offset),
-        BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K,   0x1fff, 4, 0),
+        BPF_STMT(BPF_LD  | BPF_H    | BPF_ABS, kIPv4FlagsOffset),
+        BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K,   IP_OFFMASK, 4, 0),
 
         // Get the IP header length.
-        BPF_STMT(BPF_LDX | BPF_B    | BPF_MSH, ip_offset),
+        BPF_STMT(BPF_LDX | BPF_B    | BPF_MSH, kEtherHeaderLen),
 
         // Check the destination port.
-        BPF_STMT(BPF_LD  | BPF_H    | BPF_IND, dport_indirect_offset),
+        BPF_STMT(BPF_LD  | BPF_H    | BPF_IND, kUDPDstPortIndirectOffset),
         BPF_JUMP(BPF_JMP | BPF_JEQ  | BPF_K,   kDhcpClientPort, 0, 1),
 
         // Accept or reject.
@@ -93,17 +98,13 @@
         return;
     }
 
-    uint32_t ipv6_offset = sizeof(ether_header);
-    uint32_t ipv6_next_header_offset = ipv6_offset + offsetof(ip6_hdr, ip6_nxt);
-    uint32_t icmp6_offset = ipv6_offset + sizeof(ip6_hdr);
-    uint32_t icmp6_type_offset = icmp6_offset + offsetof(icmp6_hdr, icmp6_type);
     struct sock_filter filter_code[] = {
         // Check IPv6 Next Header is ICMPv6.
-        BPF_STMT(BPF_LD  | BPF_B   | BPF_ABS,  ipv6_next_header_offset),
+        BPF_STMT(BPF_LD  | BPF_B   | BPF_ABS,  kIPv6NextHeader),
         BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K,    IPPROTO_ICMPV6, 0, 3),
 
         // Check ICMPv6 type is Router Advertisement.
-        BPF_STMT(BPF_LD  | BPF_B   | BPF_ABS,  icmp6_type_offset),
+        BPF_STMT(BPF_LD  | BPF_B   | BPF_ABS,  kICMPv6TypeOffset),
         BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K,    ND_ROUTER_ADVERT, 0, 1),
 
         // Accept or reject.
@@ -122,6 +123,81 @@
     }
 }
 
+// TODO: Move all this filter code into libnetutils.
+static void android_net_utils_attachControlPacketFilter(
+        JNIEnv *env, jobject clazz, jobject javaFd, jint hardwareAddressType) {
+    if (hardwareAddressType != ARPHRD_ETHER) {
+        jniThrowExceptionFmt(env, "java/net/SocketException",
+                "attachControlPacketFilter only supports ARPHRD_ETHER");
+        return;
+    }
+
+    // Capture all:
+    //     - ARPs
+    //     - DHCPv4 packets
+    //     - Router Advertisements & Solicitations
+    //     - Neighbor Advertisements & Solicitations
+    //
+    // tcpdump:
+    //     arp or
+    //     '(ip and udp port 68)' or
+    //     '(icmp6 and ip6[40] >= 133 and ip6[40] <= 136)'
+    struct sock_filter filter_code[] = {
+        // Load the link layer next payload field.
+        BPF_STMT(BPF_LD  | BPF_H   | BPF_ABS,  kEtherTypeOffset),
+
+        // Accept all ARP.
+        // TODO: Figure out how to better filter ARPs on noisy networks.
+        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_ARP, 16, 0),
+
+        // If IPv4:
+        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_IP, 0, 9),
+
+        // Check the protocol is UDP.
+        BPF_STMT(BPF_LD  | BPF_B   | BPF_ABS,  kIPv4Protocol),
+        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K,    IPPROTO_UDP, 0, 14),
+
+        // Check this is not a fragment.
+        BPF_STMT(BPF_LD  | BPF_H    | BPF_ABS, kIPv4FlagsOffset),
+        BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K,   IP_OFFMASK, 12, 0),
+
+        // Get the IP header length.
+        BPF_STMT(BPF_LDX | BPF_B    | BPF_MSH, kEtherHeaderLen),
+
+        // Check the source port.
+        BPF_STMT(BPF_LD  | BPF_H    | BPF_IND, kUDPSrcPortIndirectOffset),
+        BPF_JUMP(BPF_JMP | BPF_JEQ  | BPF_K,   kDhcpClientPort, 8, 0),
+
+        // Check the destination port.
+        BPF_STMT(BPF_LD  | BPF_H    | BPF_IND, kUDPDstPortIndirectOffset),
+        BPF_JUMP(BPF_JMP | BPF_JEQ  | BPF_K,   kDhcpClientPort, 6, 7),
+
+        // IPv6 ...
+        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_IPV6, 0, 6),
+        // ... check IPv6 Next Header is ICMPv6 (ignore fragments), ...
+        BPF_STMT(BPF_LD  | BPF_B   | BPF_ABS,  kIPv6NextHeader),
+        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K,    IPPROTO_ICMPV6, 0, 4),
+        // ... and check the ICMPv6 type is one of RS/RA/NS/NA.
+        BPF_STMT(BPF_LD  | BPF_B   | BPF_ABS,  kICMPv6TypeOffset),
+        BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K,    ND_ROUTER_SOLICIT, 0, 2),
+        BPF_JUMP(BPF_JMP | BPF_JGT | BPF_K,    ND_NEIGHBOR_ADVERT, 1, 0),
+
+        // Accept or reject.
+        BPF_STMT(BPF_RET | BPF_K,              0xffff),
+        BPF_STMT(BPF_RET | BPF_K,              0)
+    };
+    struct sock_fprog filter = {
+        sizeof(filter_code) / sizeof(filter_code[0]),
+        filter_code,
+    };
+
+    int fd = jniGetFDFromFileDescriptor(env, javaFd);
+    if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
+        jniThrowExceptionFmt(env, "java/net/SocketException",
+                "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
+    }
+}
+
 static void android_net_utils_setupRaSocket(JNIEnv *env, jobject clazz, jobject javaFd,
         jint ifIndex)
 {
@@ -263,6 +339,7 @@
     { "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess },
     { "attachDhcpFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDhcpFilter },
     { "attachRaFilter", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_attachRaFilter },
+    { "attachControlPacketFilter", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_attachControlPacketFilter },
     { "setupRaSocket", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_setupRaSocket },
 };
 
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index 740b24d..2ae4a17 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -26,10 +26,11 @@
 #include <JNIHelp.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <android/hidl/base/1.0/IBase.h>
-#include <android/hidl/base/1.0/IHwBase.h>
+#include <android/hidl/base/1.0/BpBase.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <hidl/ServiceManagement.h>
 #include <hidl/Status.h>
+#include <hidl/HidlTransportSupport.h>
 #include <hwbinder/ProcessState.h>
 #include <nativehelper/ScopedLocalRef.h>
 
@@ -241,14 +242,8 @@
     using android::hidl::manager::V1_0::IServiceManager;
 
     sp<hardware::IBinder> binder = JHwBinder::GetNativeContext(env, thiz);
-
-    sp<hidl::base::V1_0::IBase> base = hidl::base::V1_0::IHwBase::asInterface(binder);
-    if (base.get() == nullptr) {
-        LOG(ERROR) << "IBinder object cannot be casted to the base interface.";
-        signalExceptionForError(env, UNKNOWN_ERROR);
-        return;
-    }
-
+    /* TODO(b/33440494) this is not right */
+    sp<hidl::base::V1_0::IBase> base = new hidl::base::V1_0::BpBase(binder);
     bool ok = hardware::defaultServiceManager()->add(
                 interfaceChain,
                 serviceName,
@@ -300,7 +295,7 @@
             serviceName,
             [&service](sp<hidl::base::V1_0::IBase> out) {
                 service = hardware::toBinder<
-                        hidl::base::V1_0::IBase, hidl::base::V1_0::IHwBase
+                        hidl::base::V1_0::IBase, hidl::base::V1_0::BpBase
                     >(out);
             });
 
diff --git a/core/jni/android_view_DisplayListCanvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp
index 74c073f..2c4771c 100644
--- a/core/jni/android_view_DisplayListCanvas.cpp
+++ b/core/jni/android_view_DisplayListCanvas.cpp
@@ -87,19 +87,17 @@
     sp<InvokeRunnableMessage> mMessage;
 };
 
-// ----------------------------------------------------------------------------
-// Setup
-// ----------------------------------------------------------------------------
 
-static void android_view_DisplayListCanvas_insertReorderBarrier(JNIEnv* env, jobject clazz,
-        jlong canvasPtr, jboolean reorderEnable) {
-    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
-    canvas->insertReorderBarrier(reorderEnable);
+// ---------------- Regular JNI -----------------------------
+
+static void
+android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject javaFileDescriptor) {
+    int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
+    android::uirenderer::renderthread::RenderProxy::dumpGraphicsMemory(fd);
 }
 
-// ----------------------------------------------------------------------------
-// Functor
-// ----------------------------------------------------------------------------
+
+// ---------------- @FastNative -----------------------------
 
 static void android_view_DisplayListCanvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
         jlong canvasPtr, jlong functorPtr, jobject releasedCallback) {
@@ -112,31 +110,62 @@
     canvas->callDrawGLFunction(functor, bridge.get());
 }
 
-// ----------------------------------------------------------------------------
-// Misc
-// ----------------------------------------------------------------------------
 
-static jint android_view_DisplayListCanvas_getMaxTextureWidth(JNIEnv* env, jobject clazz) {
+// ---------------- @CriticalNative -------------------------
+
+static jlong android_view_DisplayListCanvas_createDisplayListCanvas(jlong renderNodePtr,
+        jint width, jint height) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    return reinterpret_cast<jlong>(Canvas::create_recording_canvas(width, height, renderNode));
+}
+
+static void android_view_DisplayListCanvas_resetDisplayListCanvas(jlong canvasPtr,
+        jlong renderNodePtr, jint width, jint height) {
+    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    canvas->resetRecording(width, height, renderNode);
+}
+
+static jint android_view_DisplayListCanvas_getMaxTextureWidth() {
     if (!Caches::hasInstance()) {
         android::uirenderer::renderthread::RenderProxy::staticFence();
     }
     return Caches::getInstance().maxTextureSize;
 }
 
-static jint android_view_DisplayListCanvas_getMaxTextureHeight(JNIEnv* env, jobject clazz) {
+static jint android_view_DisplayListCanvas_getMaxTextureHeight() {
     if (!Caches::hasInstance()) {
         android::uirenderer::renderthread::RenderProxy::staticFence();
     }
     return Caches::getInstance().maxTextureSize;
 }
 
-// ----------------------------------------------------------------------------
-// Drawing
-// ----------------------------------------------------------------------------
+static void android_view_DisplayListCanvas_insertReorderBarrier(jlong canvasPtr,
+        jboolean reorderEnable) {
+    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
+    canvas->insertReorderBarrier(reorderEnable);
+}
 
-static void android_view_DisplayListCanvas_drawRoundRectProps(JNIEnv* env, jobject clazz,
-        jlong canvasPtr, jlong leftPropPtr, jlong topPropPtr, jlong rightPropPtr,
-        jlong bottomPropPtr, jlong rxPropPtr, jlong ryPropPtr, jlong paintPropPtr) {
+static jlong android_view_DisplayListCanvas_finishRecording(jlong canvasPtr) {
+    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
+    return reinterpret_cast<jlong>(canvas->finishRecording());
+}
+
+static void android_view_DisplayListCanvas_drawRenderNode(jlong canvasPtr, jlong renderNodePtr) {
+    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    canvas->drawRenderNode(renderNode);
+}
+
+static void android_view_DisplayListCanvas_drawLayer(jlong canvasPtr, jlong layerPtr) {
+    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
+    canvas->drawLayer(layer);
+}
+
+static void android_view_DisplayListCanvas_drawRoundRectProps(jlong canvasPtr,
+        jlong leftPropPtr, jlong topPropPtr, jlong rightPropPtr, jlong bottomPropPtr,
+        jlong rxPropPtr, jlong ryPropPtr, jlong paintPropPtr) {
     Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
     CanvasPropertyPrimitive* leftProp = reinterpret_cast<CanvasPropertyPrimitive*>(leftPropPtr);
     CanvasPropertyPrimitive* topProp = reinterpret_cast<CanvasPropertyPrimitive*>(topPropPtr);
@@ -148,8 +177,8 @@
     canvas->drawRoundRect(leftProp, topProp, rightProp, bottomProp, rxProp, ryProp, paintProp);
 }
 
-static void android_view_DisplayListCanvas_drawCircleProps(JNIEnv* env, jobject clazz,
-        jlong canvasPtr, jlong xPropPtr, jlong yPropPtr, jlong radiusPropPtr, jlong paintPropPtr) {
+static void android_view_DisplayListCanvas_drawCircleProps(jlong canvasPtr,
+        jlong xPropPtr, jlong yPropPtr, jlong radiusPropPtr, jlong paintPropPtr) {
     Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
     CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
     CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
@@ -159,58 +188,6 @@
 }
 
 // ----------------------------------------------------------------------------
-// Display lists
-// ----------------------------------------------------------------------------
-
-static jlong android_view_DisplayListCanvas_finishRecording(JNIEnv* env,
-        jobject clazz, jlong canvasPtr) {
-    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
-    return reinterpret_cast<jlong>(canvas->finishRecording());
-}
-
-static jlong android_view_DisplayListCanvas_createDisplayListCanvas(JNIEnv* env, jobject clazz,
-        jlong renderNodePtr, jint width, jint height) {
-    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
-    return reinterpret_cast<jlong>(Canvas::create_recording_canvas(width, height, renderNode));
-}
-
-static void android_view_DisplayListCanvas_resetDisplayListCanvas(JNIEnv* env, jobject clazz,
-        jlong canvasPtr, jlong renderNodePtr, jint width, jint height) {
-    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
-    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
-    canvas->resetRecording(width, height, renderNode);
-}
-
-
-static void android_view_DisplayListCanvas_drawRenderNode(JNIEnv* env,
-        jobject clazz, jlong canvasPtr, jlong renderNodePtr) {
-    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
-    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
-    canvas->drawRenderNode(renderNode);
-}
-
-// ----------------------------------------------------------------------------
-// Layers
-// ----------------------------------------------------------------------------
-
-static void android_view_DisplayListCanvas_drawLayer(JNIEnv* env, jobject clazz,
-        jlong canvasPtr, jlong layerPtr) {
-    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
-    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
-    canvas->drawLayer(layer);
-}
-
-// ----------------------------------------------------------------------------
-// Logging
-// ----------------------------------------------------------------------------
-
-static void
-android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject javaFileDescriptor) {
-    int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
-    android::uirenderer::renderthread::RenderProxy::dumpGraphicsMemory(fd);
-}
-
-// ----------------------------------------------------------------------------
 // JNI Glue
 // ----------------------------------------------------------------------------
 
@@ -220,28 +197,25 @@
 
     // ------------ @FastNative ------------------
 
-    { "nInsertReorderBarrier","(JZ)V",         (void*) android_view_DisplayListCanvas_insertReorderBarrier },
-
     { "nCallDrawGLFunction", "(JJLjava/lang/Runnable;)V",
             (void*) android_view_DisplayListCanvas_callDrawGLFunction },
 
-    { "nDrawRoundRect",     "(JJJJJJJJ)V",     (void*) android_view_DisplayListCanvas_drawRoundRectProps },
-    { "nDrawCircle",        "(JJJJJ)V",        (void*) android_view_DisplayListCanvas_drawCircleProps },
-
-    { "nFinishRecording",   "(J)J",            (void*) android_view_DisplayListCanvas_finishRecording },
-    { "nDrawRenderNode",    "(JJ)V",           (void*) android_view_DisplayListCanvas_drawRenderNode },
-
+    // ------------ @CriticalNative --------------
     { "nCreateDisplayListCanvas", "(JII)J",     (void*) android_view_DisplayListCanvas_createDisplayListCanvas },
-    { "nResetDisplayListCanvas", "(JJII)V",     (void*) android_view_DisplayListCanvas_resetDisplayListCanvas },
-
-    { "nDrawLayer",               "(JJ)V",     (void*) android_view_DisplayListCanvas_drawLayer },
-
-    { "nGetMaximumTextureWidth",  "()I",       (void*) android_view_DisplayListCanvas_getMaxTextureWidth },
-    { "nGetMaximumTextureHeight", "()I",       (void*) android_view_DisplayListCanvas_getMaxTextureHeight },
+    { "nResetDisplayListCanvas",  "(JJII)V",    (void*) android_view_DisplayListCanvas_resetDisplayListCanvas },
+    { "nGetMaximumTextureWidth",  "()I",        (void*) android_view_DisplayListCanvas_getMaxTextureWidth },
+    { "nGetMaximumTextureHeight", "()I",        (void*) android_view_DisplayListCanvas_getMaxTextureHeight },
+    { "nInsertReorderBarrier",    "(JZ)V",      (void*) android_view_DisplayListCanvas_insertReorderBarrier },
+    { "nFinishRecording",         "(J)J",       (void*) android_view_DisplayListCanvas_finishRecording },
+    { "nDrawRenderNode",          "(JJ)V",      (void*) android_view_DisplayListCanvas_drawRenderNode },
+    { "nDrawLayer",               "(JJ)V",      (void*) android_view_DisplayListCanvas_drawLayer },
+    { "nDrawCircle",              "(JJJJJ)V",   (void*) android_view_DisplayListCanvas_drawCircleProps },
+    { "nDrawRoundRect",           "(JJJJJJJJ)V",(void*) android_view_DisplayListCanvas_drawRoundRectProps },
 };
 
 static JNINativeMethod gActivityThreadMethods[] = {
-    { "dumpGraphicsInfo",        "(Ljava/io/FileDescriptor;)V",
+        // ------------ Regular JNI ------------------
+    { "nDumpGraphicsInfo",        "(Ljava/io/FileDescriptor;)V",
                                                (void*) android_app_ActivityThread_dumpGraphics }
 };
 
diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp
index 53c9ff0..bb69e27 100644
--- a/core/jni/android_view_GraphicBuffer.cpp
+++ b/core/jni/android_view_GraphicBuffer.cpp
@@ -142,6 +142,10 @@
             return kN32_SkColorType;
         case PIXEL_FORMAT_RGBX_8888:
             return kN32_SkColorType;
+        case PIXEL_FORMAT_RGBA_FP16:
+            return kRGBA_F16_SkColorType;
+        case PIXEL_FORMAT_RGBX_FP16:
+            return kRGBA_F16_SkColorType;
         case PIXEL_FORMAT_RGB_565:
             return kRGB_565_SkColorType;
         default:
@@ -197,7 +201,7 @@
     Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas);
     nativeCanvas->setBitmap(bitmap);
     nativeCanvas->clipRect(rect.left, rect.top, rect.right, rect.bottom,
-            kIntersect_SkClipOp);
+            SkClipOp::kIntersect);
 
     if (dirtyRect) {
         INVOKEV(dirtyRect, gRectClassInfo.set,
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index dd2a7a9..d75d5c1 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -51,7 +51,7 @@
     return env;
 }
 
-static jmethodID gOnRenderNodeDetached;
+static jfieldID gRenderNode_validFieldID;
 
 class RenderNodeContext : public VirtualLightRefBase {
 public:
@@ -87,7 +87,10 @@
         node->setUserContext(nullptr);
         return;
     }
-    env->CallVoidMethod(jnode, gOnRenderNodeDetached);
+
+    // Update the valid field, since native has already removed
+    // the staging DisplayList
+    env->SetBooleanField(jnode, gRenderNode_validFieldID, false);
     env->DeleteLocalRef(jnode);
 }
 
@@ -95,14 +98,12 @@
 // DisplayList view properties
 // ----------------------------------------------------------------------------
 
-static void android_view_RenderNode_output(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
+static void android_view_RenderNode_output(JNIEnv* env, jobject clazz, jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->output();
 }
 
-static jint android_view_RenderNode_getDebugSize(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
+static jint android_view_RenderNode_getDebugSize(JNIEnv* env, jobject clazz, jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     return renderNode->getDebugSize();
 }
@@ -153,59 +154,53 @@
 // RenderProperties - setters
 // ----------------------------------------------------------------------------
 
-static jboolean android_view_RenderNode_setLayerType(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, jint jlayerType) {
+static jboolean android_view_RenderNode_setLayerType(jlong renderNodePtr, jint jlayerType) {
     LayerType layerType = static_cast<LayerType>(jlayerType);
     return SET_AND_DIRTY(mutateLayerProperties().setType, layerType, RenderNode::GENERIC);
 }
 
-static jboolean android_view_RenderNode_setLayerPaint(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, jlong paintPtr) {
+static jboolean android_view_RenderNode_setLayerPaint(jlong renderNodePtr, jlong paintPtr) {
     Paint* paint = reinterpret_cast<Paint*>(paintPtr);
     return SET_AND_DIRTY(mutateLayerProperties().setFromPaint, paint, RenderNode::GENERIC);
 }
 
-static jboolean android_view_RenderNode_setStaticMatrix(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, jlong matrixPtr) {
+static jboolean android_view_RenderNode_setStaticMatrix(jlong renderNodePtr, jlong matrixPtr) {
     SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
     return SET_AND_DIRTY(setStaticMatrix, matrix, RenderNode::GENERIC);
 }
 
-static jboolean android_view_RenderNode_setAnimationMatrix(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, jlong matrixPtr) {
+static jboolean android_view_RenderNode_setAnimationMatrix(jlong renderNodePtr, jlong matrixPtr) {
     SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
     return SET_AND_DIRTY(setAnimationMatrix, matrix, RenderNode::GENERIC);
 }
 
-static jboolean android_view_RenderNode_setClipToBounds(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, jboolean clipToBounds) {
+static jboolean android_view_RenderNode_setClipToBounds(jlong renderNodePtr,
+        jboolean clipToBounds) {
     return SET_AND_DIRTY(setClipToBounds, clipToBounds, RenderNode::GENERIC);
 }
 
-static jboolean android_view_RenderNode_setClipBounds(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, jint left, jint top, jint right, jint bottom) {
+static jboolean android_view_RenderNode_setClipBounds(jlong renderNodePtr,
+        jint left, jint top, jint right, jint bottom) {
     android::uirenderer::Rect clipBounds(left, top, right, bottom);
     return SET_AND_DIRTY(setClipBounds, clipBounds, RenderNode::GENERIC);
 }
 
-static jboolean android_view_RenderNode_setClipBoundsEmpty(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
+static jboolean android_view_RenderNode_setClipBoundsEmpty(jlong renderNodePtr) {
     return SET_AND_DIRTY(setClipBoundsEmpty,, RenderNode::GENERIC);
 }
 
-static jboolean android_view_RenderNode_setProjectBackwards(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, jboolean shouldProject) {
+static jboolean android_view_RenderNode_setProjectBackwards(jlong renderNodePtr,
+        jboolean shouldProject) {
     return SET_AND_DIRTY(setProjectBackwards, shouldProject, RenderNode::GENERIC);
 }
 
-static jboolean android_view_RenderNode_setProjectionReceiver(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, jboolean shouldRecieve) {
+static jboolean android_view_RenderNode_setProjectionReceiver(jlong renderNodePtr,
+        jboolean shouldRecieve) {
     return SET_AND_DIRTY(setProjectionReceiver, shouldRecieve, RenderNode::GENERIC);
 }
 
-static jboolean android_view_RenderNode_setOutlineRoundRect(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, jint left, jint top,
-        jint right, jint bottom, jfloat radius, jfloat alpha) {
+static jboolean android_view_RenderNode_setOutlineRoundRect(jlong renderNodePtr,
+        jint left, jint top, jint right, jint bottom, jfloat radius, jfloat alpha) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().mutableOutline().setRoundRect(left, top, right, bottom,
             radius, alpha);
@@ -213,8 +208,8 @@
     return true;
 }
 
-static jboolean android_view_RenderNode_setOutlineConvexPath(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, jlong outlinePathPtr, jfloat alpha) {
+static jboolean android_view_RenderNode_setOutlineConvexPath(jlong renderNodePtr,
+        jlong outlinePathPtr, jfloat alpha) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     SkPath* outlinePath = reinterpret_cast<SkPath*>(outlinePathPtr);
     renderNode->mutateStagingProperties().mutableOutline().setConvexPath(outlinePath, alpha);
@@ -222,38 +217,34 @@
     return true;
 }
 
-static jboolean android_view_RenderNode_setOutlineEmpty(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
+static jboolean android_view_RenderNode_setOutlineEmpty(jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().mutableOutline().setEmpty();
     renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
     return true;
 }
 
-static jboolean android_view_RenderNode_setOutlineNone(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
+static jboolean android_view_RenderNode_setOutlineNone(jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().mutableOutline().setNone();
     renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
     return true;
 }
 
-static jboolean android_view_RenderNode_hasShadow(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
+static jboolean android_view_RenderNode_hasShadow(jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     return renderNode->stagingProperties().hasShadow();
 }
 
-static jboolean android_view_RenderNode_setClipToOutline(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, jboolean clipToOutline) {
+static jboolean android_view_RenderNode_setClipToOutline(jlong renderNodePtr,
+        jboolean clipToOutline) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().mutableOutline().setShouldClip(clipToOutline);
     renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
     return true;
 }
 
-static jboolean android_view_RenderNode_setRevealClip(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, jboolean shouldClip,
+static jboolean android_view_RenderNode_setRevealClip(jlong renderNodePtr, jboolean shouldClip,
         jfloat x, jfloat y, jfloat radius) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().mutableRevealClip().set(
@@ -262,100 +253,82 @@
     return true;
 }
 
-static jboolean android_view_RenderNode_setAlpha(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, float alpha) {
+static jboolean android_view_RenderNode_setAlpha(jlong renderNodePtr, float alpha) {
     return SET_AND_DIRTY(setAlpha, alpha, RenderNode::ALPHA);
 }
 
-static jboolean android_view_RenderNode_setHasOverlappingRendering(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, bool hasOverlappingRendering) {
+static jboolean android_view_RenderNode_setHasOverlappingRendering(jlong renderNodePtr,
+        bool hasOverlappingRendering) {
     return SET_AND_DIRTY(setHasOverlappingRendering, hasOverlappingRendering,
             RenderNode::GENERIC);
 }
 
-static jboolean android_view_RenderNode_setElevation(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, float elevation) {
+static jboolean android_view_RenderNode_setElevation(jlong renderNodePtr, float elevation) {
     return SET_AND_DIRTY(setElevation, elevation, RenderNode::Z);
 }
 
-static jboolean android_view_RenderNode_setTranslationX(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, float tx) {
+static jboolean android_view_RenderNode_setTranslationX(jlong renderNodePtr, float tx) {
     return SET_AND_DIRTY(setTranslationX, tx, RenderNode::TRANSLATION_X | RenderNode::X);
 }
 
-static jboolean android_view_RenderNode_setTranslationY(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, float ty) {
+static jboolean android_view_RenderNode_setTranslationY(jlong renderNodePtr, float ty) {
     return SET_AND_DIRTY(setTranslationY, ty, RenderNode::TRANSLATION_Y | RenderNode::Y);
 }
 
-static jboolean android_view_RenderNode_setTranslationZ(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, float tz) {
+static jboolean android_view_RenderNode_setTranslationZ(jlong renderNodePtr, float tz) {
     return SET_AND_DIRTY(setTranslationZ, tz, RenderNode::TRANSLATION_Z | RenderNode::Z);
 }
 
-static jboolean android_view_RenderNode_setRotation(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, float rotation) {
+static jboolean android_view_RenderNode_setRotation(jlong renderNodePtr, float rotation) {
     return SET_AND_DIRTY(setRotation, rotation, RenderNode::ROTATION);
 }
 
-static jboolean android_view_RenderNode_setRotationX(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, float rx) {
+static jboolean android_view_RenderNode_setRotationX(jlong renderNodePtr, float rx) {
     return SET_AND_DIRTY(setRotationX, rx, RenderNode::ROTATION_X);
 }
 
-static jboolean android_view_RenderNode_setRotationY(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, float ry) {
+static jboolean android_view_RenderNode_setRotationY(jlong renderNodePtr, float ry) {
     return SET_AND_DIRTY(setRotationY, ry, RenderNode::ROTATION_Y);
 }
 
-static jboolean android_view_RenderNode_setScaleX(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, float sx) {
+static jboolean android_view_RenderNode_setScaleX(jlong renderNodePtr, float sx) {
     return SET_AND_DIRTY(setScaleX, sx, RenderNode::SCALE_X);
 }
 
-static jboolean android_view_RenderNode_setScaleY(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, float sy) {
+static jboolean android_view_RenderNode_setScaleY(jlong renderNodePtr, float sy) {
     return SET_AND_DIRTY(setScaleY, sy, RenderNode::SCALE_Y);
 }
 
-static jboolean android_view_RenderNode_setPivotX(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, float px) {
+static jboolean android_view_RenderNode_setPivotX(jlong renderNodePtr, float px) {
     return SET_AND_DIRTY(setPivotX, px, RenderNode::GENERIC);
 }
 
-static jboolean android_view_RenderNode_setPivotY(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, float py) {
+static jboolean android_view_RenderNode_setPivotY(jlong renderNodePtr, float py) {
     return SET_AND_DIRTY(setPivotY, py, RenderNode::GENERIC);
 }
 
-static jboolean android_view_RenderNode_setCameraDistance(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, float distance) {
+static jboolean android_view_RenderNode_setCameraDistance(jlong renderNodePtr, float distance) {
     return SET_AND_DIRTY(setCameraDistance, distance, RenderNode::GENERIC);
 }
 
-static jboolean android_view_RenderNode_setLeft(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, int left) {
+static jboolean android_view_RenderNode_setLeft(jlong renderNodePtr, int left) {
     return SET_AND_DIRTY(setLeft, left, RenderNode::X);
 }
 
-static jboolean android_view_RenderNode_setTop(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, int top) {
+static jboolean android_view_RenderNode_setTop(jlong renderNodePtr, int top) {
     return SET_AND_DIRTY(setTop, top, RenderNode::Y);
 }
 
-static jboolean android_view_RenderNode_setRight(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, int right) {
+static jboolean android_view_RenderNode_setRight(jlong renderNodePtr, int right) {
     return SET_AND_DIRTY(setRight, right, RenderNode::X);
 }
 
-static jboolean android_view_RenderNode_setBottom(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, int bottom) {
+static jboolean android_view_RenderNode_setBottom(jlong renderNodePtr, int bottom) {
     return SET_AND_DIRTY(setBottom, bottom, RenderNode::Y);
 }
 
-static jboolean android_view_RenderNode_setLeftTopRightBottom(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, int left, int top,
-        int right, int bottom) {
+static jboolean android_view_RenderNode_setLeftTopRightBottom(jlong renderNodePtr,
+        int left, int top, int right, int bottom) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     if (renderNode->mutateStagingProperties().setLeftTopRightBottom(left, top, right, bottom)) {
         renderNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
@@ -364,13 +337,11 @@
     return false;
 }
 
-static jboolean android_view_RenderNode_offsetLeftAndRight(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, jint offset) {
+static jboolean android_view_RenderNode_offsetLeftAndRight(jlong renderNodePtr, jint offset) {
     return SET_AND_DIRTY(offsetLeftRight, offset, RenderNode::X);
 }
 
-static jboolean android_view_RenderNode_offsetTopAndBottom(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, jint offset) {
+static jboolean android_view_RenderNode_offsetTopAndBottom(jlong renderNodePtr, jint offset) {
     return SET_AND_DIRTY(offsetTopBottom, offset, RenderNode::Y);
 }
 
@@ -378,92 +349,77 @@
 // RenderProperties - getters
 // ----------------------------------------------------------------------------
 
-static jboolean android_view_RenderNode_hasOverlappingRendering(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
+static jboolean android_view_RenderNode_hasOverlappingRendering(jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     return renderNode->stagingProperties().hasOverlappingRendering();
 }
 
-static jboolean android_view_RenderNode_getClipToOutline(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
+static jboolean android_view_RenderNode_getClipToOutline(jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     return renderNode->stagingProperties().getOutline().getShouldClip();
 }
 
-static jfloat android_view_RenderNode_getAlpha(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
+static jfloat android_view_RenderNode_getAlpha(jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     return renderNode->stagingProperties().getAlpha();
 }
 
-static jfloat android_view_RenderNode_getCameraDistance(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
+static jfloat android_view_RenderNode_getCameraDistance(jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     return renderNode->stagingProperties().getCameraDistance();
 }
 
-static jfloat android_view_RenderNode_getScaleX(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
+static jfloat android_view_RenderNode_getScaleX(jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     return renderNode->stagingProperties().getScaleX();
 }
 
-static jfloat android_view_RenderNode_getScaleY(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
+static jfloat android_view_RenderNode_getScaleY(jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     return renderNode->stagingProperties().getScaleY();
 }
 
-static jfloat android_view_RenderNode_getElevation(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
+static jfloat android_view_RenderNode_getElevation(jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     return renderNode->stagingProperties().getElevation();
 }
 
-static jfloat android_view_RenderNode_getTranslationX(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
+static jfloat android_view_RenderNode_getTranslationX(jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     return renderNode->stagingProperties().getTranslationX();
 }
 
-static jfloat android_view_RenderNode_getTranslationY(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
+static jfloat android_view_RenderNode_getTranslationY(jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     return renderNode->stagingProperties().getTranslationY();
 }
 
-static jfloat android_view_RenderNode_getTranslationZ(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
+static jfloat android_view_RenderNode_getTranslationZ(jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     return renderNode->stagingProperties().getTranslationZ();
 }
 
-static jfloat android_view_RenderNode_getRotation(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
+static jfloat android_view_RenderNode_getRotation(jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     return renderNode->stagingProperties().getRotation();
 }
 
-static jfloat android_view_RenderNode_getRotationX(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
+static jfloat android_view_RenderNode_getRotationX(jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     return renderNode->stagingProperties().getRotationX();
 }
 
-static jfloat android_view_RenderNode_getRotationY(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
+static jfloat android_view_RenderNode_getRotationY(jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     return renderNode->stagingProperties().getRotationY();
 }
 
-static jboolean android_view_RenderNode_isPivotExplicitlySet(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
+static jboolean android_view_RenderNode_isPivotExplicitlySet(jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     return renderNode->stagingProperties().isPivotExplicitlySet();
 }
 
-static jboolean android_view_RenderNode_hasIdentityMatrix(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
+static jboolean android_view_RenderNode_hasIdentityMatrix(jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().updateMatrix();
     return !renderNode->stagingProperties().hasTransformMatrix();
@@ -473,8 +429,7 @@
 // RenderProperties - computed getters
 // ----------------------------------------------------------------------------
 
-static void android_view_RenderNode_getTransformMatrix(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, jlong outMatrixPtr) {
+static void android_view_RenderNode_getTransformMatrix(jlong renderNodePtr, jlong outMatrixPtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     SkMatrix* outMatrix = reinterpret_cast<SkMatrix*>(outMatrixPtr);
 
@@ -488,10 +443,10 @@
     }
 }
 
-static void android_view_RenderNode_getInverseTransformMatrix(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, jlong outMatrixPtr) {
+static void android_view_RenderNode_getInverseTransformMatrix(jlong renderNodePtr,
+        jlong outMatrixPtr) {
     // load transform matrix
-    android_view_RenderNode_getTransformMatrix(env, clazz, renderNodePtr, outMatrixPtr);
+    android_view_RenderNode_getTransformMatrix(renderNodePtr, outMatrixPtr);
     SkMatrix* outMatrix = reinterpret_cast<SkMatrix*>(outMatrixPtr);
 
     // return it inverted
@@ -501,15 +456,13 @@
     }
 }
 
-static jfloat android_view_RenderNode_getPivotX(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
+static jfloat android_view_RenderNode_getPivotX(jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().updateMatrix();
     return renderNode->stagingProperties().getPivotX();
 }
 
-static jfloat android_view_RenderNode_getPivotY(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
+static jfloat android_view_RenderNode_getPivotY(jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().updateMatrix();
     return renderNode->stagingProperties().getPivotY();
@@ -519,8 +472,8 @@
 // RenderProperties - Animations
 // ----------------------------------------------------------------------------
 
-static void android_view_RenderNode_addAnimator(JNIEnv* env, jobject clazz,
-        jlong renderNodePtr, jlong animatorPtr) {
+static void android_view_RenderNode_addAnimator(JNIEnv* env, jobject clazz, jlong renderNodePtr,
+        jlong animatorPtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     RenderPropertyAnimator* animator = reinterpret_cast<RenderPropertyAnimator*>(animatorPtr);
     renderNode->addAnimator(animator);
@@ -651,15 +604,22 @@
 // ----------------------------------------------------------------------------
     { "nCreate",               "(Ljava/lang/String;)J", (void*) android_view_RenderNode_create },
     { "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 },
     { "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 },
+    { "nSetDisplayList",       "(JJ)V",   (void*) android_view_RenderNode_setDisplayList },
+
 
 // ----------------------------------------------------------------------------
-// Fast JNI via @FastNative annotation in RenderNode.java
+// Fast JNI via @CriticalNative annotation in RenderNode.java
+// ----------------------------------------------------------------------------
+    { "nSetDisplayList",       "(JJ)V",   (void*) android_view_RenderNode_setDisplayList },
+
+
+// ----------------------------------------------------------------------------
+// Critical JNI via @CriticalNative annotation in RenderNode.java
 // ----------------------------------------------------------------------------
     { "nSetLayerType",         "(JI)Z",  (void*) android_view_RenderNode_setLayerType },
     { "nSetLayerPaint",        "(JJ)Z",  (void*) android_view_RenderNode_setLayerPaint },
@@ -732,8 +692,7 @@
     gSurfaceViewPositionLostMethod = GetMethodIDOrDie(env, clazz,
             "windowPositionLost_uiRtSync", "(J)V");
     clazz = FindClassOrDie(env, "android/view/RenderNode");
-    gOnRenderNodeDetached = GetMethodIDOrDie(env, clazz,
-            "onRenderNodeDetached", "()V");
+    gRenderNode_validFieldID = GetFieldIDOrDie(env, clazz, "mValid", "Z");
     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 63997e5..a5b7671 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -168,6 +168,8 @@
     switch(format) {
         case HAL_PIXEL_FORMAT_RGBA_8888:
         case HAL_PIXEL_FORMAT_RGBX_8888:
+        case HAL_PIXEL_FORMAT_RGBA_FP16:
+        case HAL_PIXEL_FORMAT_RGBX_FP16:
         case HAL_PIXEL_FORMAT_RGB_888:
         case HAL_PIXEL_FORMAT_RGB_565:
         case HAL_PIXEL_FORMAT_Y8:
@@ -283,6 +285,8 @@
     switch (format) {
     case PIXEL_FORMAT_RGBX_8888:    return kN32_SkColorType;
     case PIXEL_FORMAT_RGBA_8888:    return kN32_SkColorType;
+    case PIXEL_FORMAT_RGBX_FP16:    return kRGBA_F16_SkColorType;
+    case PIXEL_FORMAT_RGBA_FP16:    return kRGBA_F16_SkColorType;
     case PIXEL_FORMAT_RGB_565:      return kRGB_565_SkColorType;
     default:                        return kUnknown_SkColorType;
     }
@@ -339,7 +343,7 @@
 
     if (dirtyRectPtr) {
         nativeCanvas->clipRect(dirtyRect.left, dirtyRect.top,
-                dirtyRect.right, dirtyRect.bottom, kIntersect_SkClipOp);
+                dirtyRect.right, dirtyRect.bottom, SkClipOp::kIntersect);
     }
 
     if (dirtyRectObj) {
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 5b88181..62c3d04 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -164,6 +164,16 @@
             alphaType = kPremul_SkAlphaType;
             break;
         }
+        case PIXEL_FORMAT_RGBX_FP16: {
+            colorType = kRGBA_F16_SkColorType;
+            alphaType = kOpaque_SkAlphaType;
+            break;
+        }
+        case PIXEL_FORMAT_RGBA_FP16: {
+            colorType = kRGBA_F16_SkColorType;
+            alphaType = kPremul_SkAlphaType;
+            break;
+        }
         case PIXEL_FORMAT_RGB_565: {
             colorType = kRGB_565_SkColorType;
             alphaType = kOpaque_SkAlphaType;
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index 351dce9..d3c0202 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -83,6 +83,14 @@
             colorType = kN32_SkColorType;
             alphaType = kOpaque_SkAlphaType;
             break;
+        case WINDOW_FORMAT_RGBA_FP16:
+            colorType = kRGBA_F16_SkColorType;
+            alphaType = kPremul_SkAlphaType;
+            break;
+        case WINDOW_FORMAT_RGBX_FP16:
+            colorType = kRGBA_F16_SkColorType;
+            alphaType = kOpaque_SkAlphaType;
+            break;
         case WINDOW_FORMAT_RGB_565:
             colorType = kRGB_565_SkColorType;
             alphaType = kOpaque_SkAlphaType;
@@ -167,7 +175,7 @@
     Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas);
     nativeCanvas->setBitmap(bitmap);
     nativeCanvas->clipRect(rect.left, rect.top, rect.right, rect.bottom,
-            kIntersect_SkClipOp);
+            SkClipOp::kIntersect);
 
     if (dirtyRect) {
         INVOKEV(dirtyRect, gRectClassInfo.set,
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index 7e01657..f8f9efe 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -49,9 +49,6 @@
 
 #define RS_BITCODE_SUFFIX ".bc"
 
-#define GDBSERVER "gdbserver"
-#define GDBSERVER_LEN (sizeof(GDBSERVER) - 1)
-
 #define TMP_FILE_PATTERN "/tmp.XXXXXX"
 #define TMP_FILE_PATTERN_LEN (sizeof(TMP_FILE_PATTERN) - 1)
 
@@ -246,7 +243,7 @@
         return INSTALL_FAILED_INTERNAL_ERROR;
     }
 
-    *(localFileName + nativeLibPath.size()) = '/';
+    *(localTmpFileName + nativeLibPath.size()) = '/';
 
     if (strlcpy(localTmpFileName + nativeLibPath.size(), TMP_FILE_PATTERN,
                     TMP_FILE_PATTERN_LEN - nativeLibPath.size()) != TMP_FILE_PATTERN_LEN) {
@@ -313,20 +310,20 @@
  */
 class NativeLibrariesIterator {
 private:
-    NativeLibrariesIterator(ZipFileRO* zipFile, void* cookie)
-        : mZipFile(zipFile), mCookie(cookie), mLastSlash(NULL) {
+    NativeLibrariesIterator(ZipFileRO* zipFile, bool debuggable, void* cookie)
+        : mZipFile(zipFile), mDebuggable(debuggable), mCookie(cookie), mLastSlash(NULL) {
         fileName[0] = '\0';
     }
 
 public:
-    static NativeLibrariesIterator* create(ZipFileRO* zipFile) {
+    static NativeLibrariesIterator* create(ZipFileRO* zipFile, bool debuggable) {
         void* cookie = NULL;
         // Do not specify a suffix to find both .so files and gdbserver.
         if (!zipFile->startIteration(&cookie, APK_LIB, NULL /* suffix */)) {
             return NULL;
         }
 
-        return new NativeLibrariesIterator(zipFile, cookie);
+        return new NativeLibrariesIterator(zipFile, debuggable, cookie);
     }
 
     ZipEntryRO next() {
@@ -347,15 +344,8 @@
             const char* lastSlash = strrchr(fileName, '/');
             ALOG_ASSERT(lastSlash != NULL, "last slash was null somehow for %s\n", fileName);
 
-            // Exception: If we find the gdbserver binary, return it.
-            if (!strncmp(lastSlash + 1, GDBSERVER, GDBSERVER_LEN)) {
-                mLastSlash = lastSlash;
-                break;
-            }
-
-            // Make sure the filename starts with lib and ends with ".so".
-            if (strncmp(fileName + fileNameLen - LIB_SUFFIX_LEN, LIB_SUFFIX, LIB_SUFFIX_LEN)
-                || strncmp(lastSlash, LIB_PREFIX, LIB_PREFIX_LEN)) {
+            // Skip directories.
+            if (*(lastSlash + 1) == 0) {
                 continue;
             }
 
@@ -364,6 +354,14 @@
                 continue;
             }
 
+            if (!mDebuggable) {
+              // Make sure the filename starts with lib and ends with ".so".
+              if (strncmp(fileName + fileNameLen - LIB_SUFFIX_LEN, LIB_SUFFIX, LIB_SUFFIX_LEN)
+                  || strncmp(lastSlash, LIB_PREFIX, LIB_PREFIX_LEN)) {
+                  continue;
+              }
+            }
+
             mLastSlash = lastSlash;
             break;
         }
@@ -386,19 +384,21 @@
 
     char fileName[PATH_MAX];
     ZipFileRO* const mZipFile;
+    const bool mDebuggable;
     void* mCookie;
     const char* mLastSlash;
 };
 
 static install_status_t
 iterateOverNativeFiles(JNIEnv *env, jlong apkHandle, jstring javaCpuAbi,
-                       iterFunc callFunc, void* callArg) {
+                       jboolean debuggable, iterFunc callFunc, void* callArg) {
     ZipFileRO* zipFile = reinterpret_cast<ZipFileRO*>(apkHandle);
     if (zipFile == NULL) {
         return INSTALL_FAILED_INVALID_APK;
     }
 
-    std::unique_ptr<NativeLibrariesIterator> it(NativeLibrariesIterator::create(zipFile));
+    std::unique_ptr<NativeLibrariesIterator> it(
+            NativeLibrariesIterator::create(zipFile, debuggable));
     if (it.get() == NULL) {
         return INSTALL_FAILED_INVALID_APK;
     }
@@ -432,7 +432,8 @@
 }
 
 
-static int findSupportedAbi(JNIEnv *env, jlong apkHandle, jobjectArray supportedAbisArray) {
+static int findSupportedAbi(JNIEnv *env, jlong apkHandle, jobjectArray supportedAbisArray,
+        jboolean debuggable) {
     const int numAbis = env->GetArrayLength(supportedAbisArray);
     Vector<ScopedUtfChars*> supportedAbis;
 
@@ -446,7 +447,8 @@
         return INSTALL_FAILED_INVALID_APK;
     }
 
-    std::unique_ptr<NativeLibrariesIterator> it(NativeLibrariesIterator::create(zipFile));
+    std::unique_ptr<NativeLibrariesIterator> it(
+            NativeLibrariesIterator::create(zipFile, debuggable));
     if (it.get() == NULL) {
         return INSTALL_FAILED_INVALID_APK;
     }
@@ -488,29 +490,29 @@
 static jint
 com_android_internal_content_NativeLibraryHelper_copyNativeBinaries(JNIEnv *env, jclass clazz,
         jlong apkHandle, jstring javaNativeLibPath, jstring javaCpuAbi,
-        jboolean extractNativeLibs, jboolean hasNativeBridge)
+        jboolean extractNativeLibs, jboolean hasNativeBridge, jboolean debuggable)
 {
     void* args[] = { &javaNativeLibPath, &extractNativeLibs, &hasNativeBridge };
-    return (jint) iterateOverNativeFiles(env, apkHandle, javaCpuAbi,
+    return (jint) iterateOverNativeFiles(env, apkHandle, javaCpuAbi, debuggable,
             copyFileIfChanged, reinterpret_cast<void*>(args));
 }
 
 static jlong
 com_android_internal_content_NativeLibraryHelper_sumNativeBinaries(JNIEnv *env, jclass clazz,
-        jlong apkHandle, jstring javaCpuAbi)
+        jlong apkHandle, jstring javaCpuAbi, jboolean debuggable)
 {
     size_t totalSize = 0;
 
-    iterateOverNativeFiles(env, apkHandle, javaCpuAbi, sumFiles, &totalSize);
+    iterateOverNativeFiles(env, apkHandle, javaCpuAbi, debuggable, sumFiles, &totalSize);
 
     return totalSize;
 }
 
 static jint
 com_android_internal_content_NativeLibraryHelper_findSupportedAbi(JNIEnv *env, jclass clazz,
-        jlong apkHandle, jobjectArray javaCpuAbisToSearch)
+        jlong apkHandle, jobjectArray javaCpuAbisToSearch, jboolean debuggable)
 {
-    return (jint) findSupportedAbi(env, apkHandle, javaCpuAbisToSearch);
+    return (jint) findSupportedAbi(env, apkHandle, javaCpuAbisToSearch, debuggable);
 }
 
 enum bitcode_scan_result_t {
@@ -569,13 +571,13 @@
             "(J)V",
             (void *)com_android_internal_content_NativeLibraryHelper_close},
     {"nativeCopyNativeBinaries",
-            "(JLjava/lang/String;Ljava/lang/String;ZZ)I",
+            "(JLjava/lang/String;Ljava/lang/String;ZZZ)I",
             (void *)com_android_internal_content_NativeLibraryHelper_copyNativeBinaries},
     {"nativeSumNativeBinaries",
-            "(JLjava/lang/String;)J",
+            "(JLjava/lang/String;Z)J",
             (void *)com_android_internal_content_NativeLibraryHelper_sumNativeBinaries},
     {"nativeFindSupportedAbi",
-            "(J[Ljava/lang/String;)I",
+            "(J[Ljava/lang/String;Z)I",
             (void *)com_android_internal_content_NativeLibraryHelper_findSupportedAbi},
     {"hasRenderscriptBitcode", "(J)I",
             (void *)com_android_internal_content_NativeLibraryHelper_hasRenderscriptBitcode},
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index da059e3..cc7b958 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -56,7 +56,7 @@
 #include "ScopedLocalRef.h"
 #include "ScopedPrimitiveArray.h"
 #include "ScopedUtfChars.h"
-#include "fd_utils-inl.h"
+#include "fd_utils.h"
 
 #include "nativebridge/native_bridge.h"
 
@@ -709,6 +709,16 @@
   return pid;
 }
 
+static void com_android_internal_os_Zygote_nativeAllowFileAcrossFork(
+        JNIEnv* env, jclass, jstring path) {
+    ScopedUtfChars path_native(env, path);
+    const char* path_cstr = path_native.c_str();
+    if (!path_cstr) {
+        RuntimeAbort(env, __LINE__, "path_cstr == NULL");
+    }
+    FileDescriptorWhitelist::Get()->Allow(path_cstr);
+}
+
 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
@@ -753,6 +763,8 @@
       (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
     { "nativeForkSystemServer", "(II[II[[IJJ)I",
       (void *) com_android_internal_os_Zygote_nativeForkSystemServer },
+    { "nativeAllowFileAcrossFork", "(Ljava/lang/String;)V",
+      (void *) com_android_internal_os_Zygote_nativeAllowFileAcrossFork },
     { "nativeUnmountStorageOnInit", "()V",
       (void *) com_android_internal_os_Zygote_nativeUnmountStorageOnInit }
 };
diff --git a/core/jni/fd_utils-inl.h b/core/jni/fd_utils-inl.h
deleted file mode 100644
index e270911..0000000
--- a/core/jni/fd_utils-inl.h
+++ /dev/null
@@ -1,587 +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.
- */
-
-#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",
-  "/dev/socket/webview_zygote",
-  "/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) {
-  }
-
-  static bool StartsWith(const std::string& str, const std::string& prefix) {
-    return str.compare(0, prefix.size(), prefix) == 0;
-  }
-
-  static bool EndsWith(const std::string& str, const std::string& suffix) {
-    if (suffix.size() > str.size()) {
-      return false;
-    }
-
-    return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
-  }
-
-  // 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 std::string kFrameworksPrefix = "/system/framework/";
-    static const std::string kJarSuffix = ".jar";
-    if (StartsWith(path, kFrameworksPrefix) && EndsWith(path, kJarSuffix)) {
-      return true;
-    }
-
-    // Whitelist files needed for Runtime Resource Overlay, like these:
-    // /system/vendor/overlay/framework-res.apk
-    // /system/vendor/overlay-subdir/pg/framework-res.apk
-    // /vendor/overlay/framework-res.apk
-    // /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-subdir@pg@framework-res.apk@idmap
-    // See AssetManager.cpp for more details on overlay-subdir.
-    static const std::string kOverlayDir = "/system/vendor/overlay/";
-    static const std::string kVendorOverlayDir = "/vendor/overlay";
-    static const std::string kOverlaySubdir = "/system/vendor/overlay-subdir/";
-    static const std::string kApkSuffix = ".apk";
-
-    if ((StartsWith(path, kOverlayDir) || StartsWith(path, kOverlaySubdir)
-         || StartsWith(path, kVendorOverlayDir))
-        && EndsWith(path, kApkSuffix)
-        && path.find("/../") == std::string::npos) {
-      return true;
-    }
-
-    static const std::string kOverlayIdmapPrefix = "/data/resource-cache/";
-    static const std::string kOverlayIdmapSuffix = ".apk@idmap";
-    if (StartsWith(path, kOverlayIdmapPrefix) && EndsWith(path, kOverlayIdmapSuffix)
-        && path.find("/../") == std::string::npos) {
-      return true;
-    }
-
-    // All regular files that are placed under this path are whitelisted automatically.
-    static const std::string kZygoteWhitelistPath = "/vendor/zygote_whitelist/";
-    if (StartsWith(path, kZygoteWhitelistPath) && path.find("/../") == std::string::npos) {
-      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/fd_utils.cpp b/core/jni/fd_utils.cpp
new file mode 100644
index 0000000..969d336f3
--- /dev/null
+++ b/core/jni/fd_utils.cpp
@@ -0,0 +1,559 @@
+/*
+ * 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 "fd_utils.h"
+
+#include <algorithm>
+
+#include <fcntl.h>
+#include <grp.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <android-base/strings.h>
+#include <cutils/log.h>
+
+// Static whitelist of open paths that the zygote is allowed to keep open.
+static const char* kPathWhitelist[] = {
+  "/dev/null",
+  "/dev/socket/zygote",
+  "/dev/socket/zygote_secondary",
+  "/dev/socket/webview_zygote",
+  "/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";
+
+// static
+FileDescriptorWhitelist* FileDescriptorWhitelist::Get() {
+  if (instance_ == nullptr) {
+    instance_ = new FileDescriptorWhitelist();
+  }
+  return instance_;
+}
+
+bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const {
+  // Check the static whitelist path.
+  for (const auto& whitelist_path : kPathWhitelist) {
+    if (path == whitelist_path)
+      return true;
+  }
+
+  // Check any paths added to the dynamic whitelist.
+  for (const auto& whitelist_path : whitelist_) {
+    if (path == whitelist_path)
+      return true;
+  }
+
+  static const std::string kFrameworksPrefix = "/system/framework/";
+  static const std::string kJarSuffix = ".jar";
+  if (StartsWith(path, kFrameworksPrefix) && EndsWith(path, kJarSuffix)) {
+    return true;
+  }
+
+  // Whitelist files needed for Runtime Resource Overlay, like these:
+  // /system/vendor/overlay/framework-res.apk
+  // /system/vendor/overlay-subdir/pg/framework-res.apk
+  // /vendor/overlay/framework-res.apk
+  // /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-subdir@pg@framework-res.apk@idmap
+  // See AssetManager.cpp for more details on overlay-subdir.
+  static const std::string kOverlayDir = "/system/vendor/overlay/";
+  static const std::string kVendorOverlayDir = "/vendor/overlay";
+  static const std::string kOverlaySubdir = "/system/vendor/overlay-subdir/";
+  static const std::string kApkSuffix = ".apk";
+
+  if ((StartsWith(path, kOverlayDir) || StartsWith(path, kOverlaySubdir)
+       || StartsWith(path, kVendorOverlayDir))
+      && EndsWith(path, kApkSuffix)
+      && path.find("/../") == std::string::npos) {
+    return true;
+  }
+
+  static const std::string kOverlayIdmapPrefix = "/data/resource-cache/";
+  static const std::string kOverlayIdmapSuffix = ".apk@idmap";
+  if (StartsWith(path, kOverlayIdmapPrefix) && EndsWith(path, kOverlayIdmapSuffix)
+      && path.find("/../") == std::string::npos) {
+    return true;
+  }
+
+  // All regular files that are placed under this path are whitelisted automatically.
+  static const std::string kZygoteWhitelistPath = "/vendor/zygote_whitelist/";
+  if (StartsWith(path, kZygoteWhitelistPath) && path.find("/../") == std::string::npos) {
+    return true;
+  }
+
+  return false;
+}
+
+FileDescriptorWhitelist::FileDescriptorWhitelist()
+    : whitelist_() {
+}
+
+// TODO: Call android::base::StartsWith instead of copying the code here.
+// static
+bool FileDescriptorWhitelist::StartsWith(const std::string& str,
+                                         const std::string& prefix) {
+  return str.compare(0, prefix.size(), prefix) == 0;
+}
+
+// TODO: Call android::base::EndsWith instead of copying the code here.
+// static
+bool FileDescriptorWhitelist::EndsWith(const std::string& str,
+                                       const std::string& suffix) {
+  if (suffix.size() > str.size()) {
+    return false;
+  }
+
+  return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
+}
+
+FileDescriptorWhitelist* FileDescriptorWhitelist::instance_ = nullptr;
+
+// static
+FileDescriptorInfo* 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;
+  }
+
+  const FileDescriptorWhitelist* whitelist = FileDescriptorWhitelist::Get();
+
+  if (S_ISSOCK(f_stat.st_mode)) {
+    std::string socket_name;
+    if (!GetSocketName(fd, &socket_name)) {
+      return NULL;
+    }
+
+    if (!whitelist->IsAllowed(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 (!whitelist->IsAllowed(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);
+}
+
+bool FileDescriptorInfo::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 FileDescriptorInfo::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;
+}
+
+FileDescriptorInfo::FileDescriptorInfo(int fd) :
+  fd(fd),
+  stat(),
+  open_flags(0),
+  fd_flags(0),
+  fs_flags(0),
+  offset(0),
+  is_sock(true) {
+}
+
+FileDescriptorInfo::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) {
+}
+
+// TODO: Call android::base::Readlink instead of copying the code here.
+// static
+bool FileDescriptorInfo::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;
+}
+
+// static
+bool FileDescriptorInfo::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 FileDescriptorInfo::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;
+}
+
+// static
+FileDescriptorTable* 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 FileDescriptorTable::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 FileDescriptorTable::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;
+}
+
+FileDescriptorTable::FileDescriptorTable(
+    const std::unordered_map<int, FileDescriptorInfo*>& map)
+    : open_fd_map_(map) {
+}
+
+bool FileDescriptorTable::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 FileDescriptorTable::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;
+}
diff --git a/core/jni/fd_utils.h b/core/jni/fd_utils.h
new file mode 100644
index 0000000..9e3afd9
--- /dev/null
+++ b/core/jni/fd_utils.h
@@ -0,0 +1,147 @@
+/*
+ * 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 FRAMEWORKS_BASE_CORE_JNI_FD_UTILS_H_
+#define FRAMEWORKS_BASE_CORE_JNI_FD_UTILS_H_
+
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <dirent.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+
+#include <android-base/macros.h>
+
+// Whitelist of open paths that the zygote is allowed to keep open.
+//
+// In addition to the paths listed in kPathWhitelist in file_utils.cpp, and
+// paths dynamically added with Allow(), all files ending with ".jar"
+// under /system/framework" are whitelisted. See IsAllowed() 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.
+class FileDescriptorWhitelist {
+ public:
+  // Lazily creates the global whitelist.
+  static FileDescriptorWhitelist* Get();
+
+  // Adds a path to the whitelist.
+  void Allow(const std::string& path) {
+    whitelist_.push_back(path);
+  }
+
+  // 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.
+  bool IsAllowed(const std::string& path) const;
+
+ private:
+  FileDescriptorWhitelist();
+
+  static bool StartsWith(const std::string& str, const std::string& prefix);
+
+  static bool EndsWith(const std::string& str, const std::string& suffix);
+
+  static FileDescriptorWhitelist* instance_;
+
+  std::vector<std::string> whitelist_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileDescriptorWhitelist);
+};
+
+// 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);
+
+  // Checks whether the file descriptor associated with this object
+  // refers to the same description.
+  bool Restat() const;
+
+  bool ReopenOrDetach() const;
+
+  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);
+
+  FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags,
+                     int fd_flags, int fs_flags, off_t offset);
+
+  static bool Readlink(const int fd, std::string* result);
+
+  // 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);
+
+  bool DetachSocket() const;
+
+  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();
+
+  bool Restat();
+
+  // 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();
+
+ private:
+  FileDescriptorTable(const std::unordered_map<int, FileDescriptorInfo*>& map);
+
+  bool RestatInternal(std::set<int>& open_fds);
+
+  static int ParseFd(dirent* e, int dir_fd);
+
+  // Invariant: All values in this unordered_map are non-NULL.
+  std::unordered_map<int, FileDescriptorInfo*> open_fd_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileDescriptorTable);
+};
+
+#endif  // FRAMEWORKS_BASE_CORE_JNI_FD_UTILS_H_
diff --git a/include/android_runtime/AndroidRuntime.h b/core/jni/include/android_runtime/AndroidRuntime.h
similarity index 98%
rename from include/android_runtime/AndroidRuntime.h
rename to core/jni/include/android_runtime/AndroidRuntime.h
index ed77d9a..c2189d4 100644
--- a/include/android_runtime/AndroidRuntime.h
+++ b/core/jni/include/android_runtime/AndroidRuntime.h
@@ -98,7 +98,7 @@
      * Called when the Java application exits to perform additional cleanup actions
      * before the process is terminated.
      */
-    virtual void onExit(int code) { }
+    virtual void onExit(int /*code*/) { }
 
     /** create a new thread that is visible from Java */
     static android_thread_id_t createJavaThread(const char* name, void (*start)(void *),
diff --git a/include/android_runtime/Log.h b/core/jni/include/android_runtime/Log.h
similarity index 100%
rename from include/android_runtime/Log.h
rename to core/jni/include/android_runtime/Log.h
diff --git a/include/android_runtime/android_app_NativeActivity.h b/core/jni/include/android_runtime/android_app_NativeActivity.h
similarity index 100%
rename from include/android_runtime/android_app_NativeActivity.h
rename to core/jni/include/android_runtime/android_app_NativeActivity.h
diff --git a/include/android_runtime/android_content_res_Configuration.h b/core/jni/include/android_runtime/android_content_res_Configuration.h
similarity index 100%
rename from include/android_runtime/android_content_res_Configuration.h
rename to core/jni/include/android_runtime/android_content_res_Configuration.h
diff --git a/include/android_runtime/android_graphics_SurfaceTexture.h b/core/jni/include/android_runtime/android_graphics_SurfaceTexture.h
similarity index 100%
rename from include/android_runtime/android_graphics_SurfaceTexture.h
rename to core/jni/include/android_runtime/android_graphics_SurfaceTexture.h
diff --git a/include/android_runtime/android_hardware_camera2_CameraMetadata.h b/core/jni/include/android_runtime/android_hardware_camera2_CameraMetadata.h
similarity index 100%
rename from include/android_runtime/android_hardware_camera2_CameraMetadata.h
rename to core/jni/include/android_runtime/android_hardware_camera2_CameraMetadata.h
diff --git a/include/android_runtime/android_util_AssetManager.h b/core/jni/include/android_runtime/android_util_AssetManager.h
similarity index 100%
rename from include/android_runtime/android_util_AssetManager.h
rename to core/jni/include/android_runtime/android_util_AssetManager.h
diff --git a/include/android_runtime/android_view_InputQueue.h b/core/jni/include/android_runtime/android_view_InputQueue.h
similarity index 100%
rename from include/android_runtime/android_view_InputQueue.h
rename to core/jni/include/android_runtime/android_view_InputQueue.h
diff --git a/include/android_runtime/android_view_Surface.h b/core/jni/include/android_runtime/android_view_Surface.h
similarity index 100%
rename from include/android_runtime/android_view_Surface.h
rename to core/jni/include/android_runtime/android_view_Surface.h
diff --git a/include/android_runtime/android_view_SurfaceSession.h b/core/jni/include/android_runtime/android_view_SurfaceSession.h
similarity index 100%
rename from include/android_runtime/android_view_SurfaceSession.h
rename to core/jni/include/android_runtime/android_view_SurfaceSession.h
diff --git a/core/proto/android/content/component_name.proto b/core/proto/android/content/component_name.proto
new file mode 100644
index 0000000..7908af9
--- /dev/null
+++ b/core/proto/android/content/component_name.proto
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 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.
+ */
+
+syntax = "proto2";
+
+option java_package = "android.content";
+option java_multiple_files = true;
+
+package android.content;
+
+/**
+ * An android.content.ComponentName object.
+ */
+message ComponentNameProto {
+    optional string package_name = 1;
+    optional string class_name = 2;
+}
+
diff --git a/core/proto/android/content/configuration.proto b/core/proto/android/content/configuration.proto
new file mode 100644
index 0000000..683e7aac
--- /dev/null
+++ b/core/proto/android/content/configuration.proto
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 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.
+ */
+
+syntax = "proto2";
+
+option java_package = "android.content";
+option java_multiple_files = true;
+
+package android.content;
+
+import "frameworks/base/core/proto/android/content/locale.proto";
+
+/**
+ * An android resource configuration.
+ */
+message ConfigurationProto {
+  optional float font_scale = 1;
+  optional uint32 mcc = 2;
+  optional uint32 mnc = 3;
+  repeated LocaleProto locales = 4;
+  optional uint32 screen_layout = 5;
+  optional uint32 touchscreen = 6;
+  optional uint32 keyboard_hidden = 7;
+  optional uint32 hard_keyboard_hidden = 8;
+  optional uint32 navigation = 9;
+  optional uint32 navigation_hidden = 10;
+  optional uint32 orientation = 11;
+  optional uint32 ui_mode = 12;
+  optional uint32 screen_width_dp = 13;
+  optional uint32 screen_height_dp = 14;
+  optional uint32 smallest_screen_width_dp = 15;
+  optional uint32 density_dpi = 16;
+}
+
diff --git a/core/proto/android/content/locale.proto b/core/proto/android/content/locale.proto
new file mode 100644
index 0000000..55ce68e
--- /dev/null
+++ b/core/proto/android/content/locale.proto
@@ -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.
+ */
+
+syntax = "proto2";
+
+option java_package = "android.content";
+option java_multiple_files = true;
+
+package android.content;
+
+message LocaleProto {
+  optional string language = 1;
+  optional string country = 2;
+  optional string variant = 3;
+}
+
diff --git a/core/proto/android/os/incident_proto.proto b/core/proto/android/os/incident_proto.proto
new file mode 100644
index 0000000..1708b81
--- /dev/null
+++ b/core/proto/android/os/incident_proto.proto
@@ -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.
+ */
+
+syntax = "proto2";
+
+option java_package = "android.os";
+option java_multiple_files = true;
+
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+import "frameworks/base/core/proto/android/service/fingerprint_proto.proto";
+
+package android.os;
+
+message IncidentHeaderProto {
+    enum Cause {
+        CAUSE_UNKNOWN = 0;
+        CAUSE_USER = 1;
+        CAUSE_ANR = 2;
+        CAUSE_CRASH = 3;
+    }
+
+    optional Cause cause = 1;
+}
+
+message IncidentProto {
+    // Incident header
+    repeated IncidentHeaderProto header = 1;
+
+    // Device information
+    //optional SystemProperties system_properties = 1000;
+
+    // Linux services
+    //optional Procrank procrank = 2000;
+    //optional PageTypeInfo page_type_info = 2001;
+    //optional KernelWakeSources kernel_wake_sources = 2002;
+
+    // System Services
+    optional android.service.fingerprint.FingerprintServiceDumpProto fingerprint = 3000;
+}
diff --git a/core/proto/android/service/fingerprint_proto.proto b/core/proto/android/service/fingerprint_proto.proto
new file mode 100644
index 0000000..b2c5000
--- /dev/null
+++ b/core/proto/android/service/fingerprint_proto.proto
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+package android.service.fingerprint;
+
+option java_multiple_files = true;
+
+message FingerprintServiceDumpProto {
+    // Each log may include multiple tuples of (user_id, num_fingerprints).
+    repeated FingerprintUserStatsProto users = 1;
+}
+
+message FingerprintUserStatsProto {
+    // Should be 0, 10, 11, 12, etc. where 0 is the owner.
+    optional int32 user_id = 1;
+
+    // The number of fingerprints registered to this user.
+    optional int32 num_fingerprints = 2;
+
+    // Normal fingerprint authentications (e.g. lockscreen).
+    optional FingerprintActionStatsProto normal = 3;
+
+    // Crypto authentications (e.g. to unlock password storage, make secure
+    // purchases, etc).
+    optional FingerprintActionStatsProto crypto = 4;
+}
+
+message FingerprintActionStatsProto {
+    // Number of accepted fingerprints.
+    optional int32 accept = 1;
+
+    // Number of rejected fingerprints.
+    optional int32 reject = 2;
+
+    // Total number of acquisitions. Should be >= accept+reject due to poor
+    // image acquisition in some cases (too fast, too slow, dirty sensor, etc.)
+    optional int32 acquire = 3;
+
+    // Total number of lockouts.
+    optional int32 lockout = 4;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 40fd881..bc04062 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3393,7 +3393,10 @@
             android:permission="android.permission.MASTER_CLEAR">
             <intent-filter
                     android:priority="100" >
-                <!-- For Checkin, Settings, etc.: action=MASTER_CLEAR -->
+                <!-- For Checkin, Settings, etc.: action=FACTORY_RESET -->
+                <action android:name="android.intent.action.FACTORY_RESET" />
+                <!-- As above until all the references to the deprecated MASTER_CLEAR get updated to
+                     FACTORY_RESET. -->
                 <action android:name="android.intent.action.MASTER_CLEAR" />
 
                 <!-- MCS always uses REMOTE_INTENT: category=MASTER_CLEAR -->
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index f9ae7cf..b640d4d 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Laat \'n program toe om installasiesessies te lees. Dit laat dit toe om besonderhede van aktiewe pakketinstallasies te sien."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"versoek installeerpakkette"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Laat \'n program toe om te versoek dat pakkette geïnstalleer word."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"vra om batteryoptimerings te ignoreer"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Laat \'n program toe om toestemming te vra om batteryoptimerings vir daardie program ignoreer."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Klop twee keer vir zoembeheer"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Kon nie legstuk byvoeg nie."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Gaan"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Tot <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Tot <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (volgende wekker)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Totdat jy dit afskakel"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Totdat jy Moenie steur nie afskakel"</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">"Vou in"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index e24ffce..7786c94 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"የባትሪ ማትባቶችን ችላ ለማለት መጠየቅ"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"አንድ መተግበሪያ ለዚያ መተግበሪያ የባትሪ ማትባቶችን ችላ ለማለት እንዲጠይቅ ይፈቅድለታል።"</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"እስከ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> ድረስ"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"እስከ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (ቀጣይ ማንቂያ)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"ይህን እስኪያጠፉት ድረስ"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"አትረብሽን እስኪያጠፉ ድረስ"</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">"ሰብስብ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index bd0a658..8a02fad 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1312,10 +1312,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"طلب تجاهل تحسينات البطارية"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"للسماح للتطبيق بطلب الإذن لتجاهل تحسينات البطارية في هذا التطبيق."</string>
     <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>
@@ -1756,7 +1754,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"حتى <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"حتى <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (التنبيه التالي)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"لحين تعطيل هذا الإعداد"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"حتى يتم تعطيل \"الرجاء عدم الإزعاج\""</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">"تصغير"</string>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 6322bfa..2c55b7e 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Tətbiqə quraşdırma sessiyalarını oxumağa yardım edir. Bu da aktiv paket quraşdırmaları haqqında məlumatları görməyə imkan verir."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"paketləri quraşdırma sorğusu"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Tətbiqə paketləri quraşdırma sorğusu göndərməyə icazə verir."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"batareya optimallaşdırmasını iqnor etmək üçün soruşun"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Tatareya optimallaşdırılmasını o tətbiq üçün iqnor edilməsinə icazə vermək məqsədilə soruşmağa tətbiqə icazə verilir."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Zoom kontrolu üçün iki dəfə toxunun"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Widget əlavə edilə bilmədi."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Get"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Saat <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> qədər"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> radəsinə qədər (növbəti siqnal)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Bunu söndürənə kimi"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"\"Narahat etməyin\" seçiminini deaktiv edənə kimi"</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">"Dağıt"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index b44b180..48fefd2 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1237,10 +1237,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Dozvoljava aplikaciji da čita sesije instaliranja. To joj dozvoljava da vidi detalje o aktivnim instalacijama paketa."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"zahtevanje paketa za instaliranje"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Omogućava da aplikacija zahteva instalaciju paketa."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"traženje dozvole za ignorisanje optimizacija baterije"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Dozvoljava aplikaciji da traži dozvolu za ignorisanje optimizacija baterije za tu aplikaciju."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Dodirnite dvaput za kontrolu zumiranja"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Nije moguće dodati vidžet."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Idi"</string>
@@ -1651,7 +1649,8 @@
     </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> (sledeći alarm)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Dok ne isključite"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Dok ne isključite režim Ne uznemiravaj"</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">"Skupi"</string>
diff --git a/core/res/res/values-be-rBY/strings.xml b/core/res/res/values-be-rBY/strings.xml
index b035e9c..adeeef3 100644
--- a/core/res/res/values-be-rBY/strings.xml
+++ b/core/res/res/values-be-rBY/strings.xml
@@ -1262,10 +1262,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"запытваць дазвол на ігнараванне аптымізацыі акумулятара"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Дазваляе праграме запытваць дазвол на ігнараванне аптымізацыі акумулятара для гэтай праграмы."</string>
     <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>
@@ -1686,7 +1684,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Да <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Да <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (наступны будзільнік)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Пакуль вы не выключыце гэта"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Пакуль вы не выключыце рэжым «Не турбаваць»"</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">"Згарнуць"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 4caa906..3359a18 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"искане за пренебрегване на оптимизациите на батерията"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Разрешава на дадено приложение да иска разрешение за пренебрегване на свързаните с него оптимизации на батерията."</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"До следващия будилник (<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Докато не изключите това"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Докато не изключите „Не безпокойте“"</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">"Свиване"</string>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index 0c73ecd..7512bae 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ব্যাটারি অপ্টিমাইজেশন উপেক্ষা করার জন্য অনুমতি চাওয়া"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"কোনো অ্যাপের জন্য ব্যাটারি অপ্টিমাইজেশন উপেক্ষা করতে সেটিকে অনুমতির চাওয়ার মঞ্জুরি দেয়৷"</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> পর্যন্ত"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> পর্যন্ত (পরবর্তী অ্যালার্ম)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"আপনার দ্বারা এটি বন্ধ করা পর্যন্ত"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"যতক্ষণ না পর্যন্ত আপনি বিরক্ত করবেন না বন্ধ করছেন"</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">"সঙ্কুচিত করুন"</string>
@@ -1687,5 +1686,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"এখনই পুনরায় সেট করুন"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"অক্ষম করা <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"কনফারেন্স কল"</string>
-    <string name="tooltip_popup_title" msgid="5253721848739260181">"সরঞ্জামটিপ"</string>
+    <string name="tooltip_popup_title" msgid="5253721848739260181">"টুলটিপ"</string>
 </resources>
diff --git a/core/res/res/values-bs-rBA/strings.xml b/core/res/res/values-bs-rBA/strings.xml
index f831874..c188416 100644
--- a/core/res/res/values-bs-rBA/strings.xml
+++ b/core/res/res/values-bs-rBA/strings.xml
@@ -1239,10 +1239,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Dozvoljava aplikaciji da čita sesije instalacija. Ovim se aplikaciji omogućava da vidi detalje o aktivnim instalacijama paketa."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"zahtijevanje paketa za instaliranje"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Omogućava aplikaciji da zahtijeva instalaciju paket ā."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"traži zanemarivanje optimizacije baterije"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Omogućava aplikaciji da traži dozvolu za zanemarivanje optimizacije baterije za tu aplikaciju."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Dodirnite dvaput za kontrolu uvećanja"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Dodavanje vidžeta nije uspjelo."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Počni"</string>
@@ -1653,7 +1651,8 @@
     </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> (sljedeći alarm)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Dok ovo ne isključite"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Dok ne isključite opciju Ne ometaj"</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">"Skupi"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 30d1706..98a96db 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permet que una aplicació llegeixi les sessions d\'instal·lació i això permet veure detalls sobre les instal·lacions de paquet actives."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"sol·licitar la instal·lació de paquets"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Permet que una aplicació sol·liciti la instal·lació de paquets."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"Demanar permís per ignorar les optimitzacions de bateria"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Permet que una aplicació demani permís per ignorar les optimitzacions de bateria per a l\'aplicació."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Piqueu dos cops per controlar el zoom"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"No s\'ha pogut afegir el widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Vés"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Fins a les <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Fins a les <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (propera alarma)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Fins que no ho desactivis"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Fins que desactivis el mode No molesteu"</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">"Replega"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index d4ffbaa..57c4d06 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1262,10 +1262,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Povoluje aplikaci číst instalační relace. Díky tomu můžete zobrazit podrobnosti o aktivních instalacích balíčku."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"odesílání žádostí o přístup k instalačním balíčkům"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Umožňuje aplikaci požádat o instalaci balíčků."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"požádat o ignorování optimalizace využití baterie"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Povoluje aplikaci požádat o oprávnění ignorovat optimalizaci využití baterie, která pro ni je nastavena."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Poklepáním můžete ovládat přiblížení"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Widget nelze přidat."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Přejít"</string>
@@ -1686,7 +1684,8 @@
     </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> (příští budík)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Dokud tuto funkci nevypnete"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Dokud nevypnete režim Nerušit"</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">"Sbalit"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 815c324..c730ce6 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Tillader, at en applikation læser installationssessioner. Dermed kan applikationen se oplysninger om aktive pakkeinstallationer."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"anmod om installation af pakker"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Tillader, at en app anmoder om installation af pakker."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"bede om at ignorere batterioptimeringer"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Gør det muligt for en app at bede om tilladelse til at ignorere batterioptimeringer for den pågældende app."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tryk to gange for zoomkontrol"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Widget kunne ikke tilføjes."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Gå"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Indtil <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Indtil <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (næste alarm)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Indtil du slår denne indstilling fra"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Indtil du slår \"Forstyr ikke\" fra"</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">"Skjul"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index c729160..167d199 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Ermöglicht der App, Installationssitzungen zu lesen. Dadurch kann sie Details aktiver Paketinstallationen abrufen."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"Installation von Paketen anfordern"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Ermöglicht der App, die Installation von Paketen anzufordern"</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"fragen, ob Akku-Leistungsoptimierungen ignoriert werden können"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Erlaubt einer App, nach der Berechtigung zum Ignorieren der Akku-Leistungsoptimierungen zu fragen."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Für Zoomeinstellung zweimal berühren"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Widget konnte nicht hinzugefügt werden."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Los"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Bis <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Bis <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (nächste Weckzeit)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Bis zur Deaktivierung"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Bis zur Deaktivierung von \"Nicht stören\""</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">"Minimieren"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 4f0d2f1..c477aec 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"αίτημα αγνόησης βελτιστοποιήσεων μπαταρίας"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Επιτρέπει σε μια εφαρμογή να ζητήσει άδεια για την αγνόηση βελτιστοποιήσεων της μπαταρίας για τη συγκεκριμένη εφαρμογή."</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Έως τις <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Μέχρι τις <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (επόμενο ξυπνητήρι)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Μέχρι να το απενεργοποιήσετε"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Μέχρι να απενεργοποιήσετε τη ρύθμιση \"Μην ενοχλείτε\""</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">"Σύμπτυξη"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index a85976d..50989b4 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Allows an application to read install sessions. This allows it to see details about active package installations."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"request install packages"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Allows an application to request installation of packages."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ask to ignore battery optimisations"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Allows an app to ask for permission to ignore battery optimisations for that app."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tap twice for zoom control"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Couldn\'t add widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Go"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Until <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Until <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (next alarm)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Until you turn this off"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Until you turn off Do Not Disturb"</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">"Collapse"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index a85976d..50989b4 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Allows an application to read install sessions. This allows it to see details about active package installations."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"request install packages"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Allows an application to request installation of packages."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ask to ignore battery optimisations"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Allows an app to ask for permission to ignore battery optimisations for that app."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tap twice for zoom control"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Couldn\'t add widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Go"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Until <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Until <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (next alarm)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Until you turn this off"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Until you turn off Do Not Disturb"</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">"Collapse"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index a85976d..50989b4 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Allows an application to read install sessions. This allows it to see details about active package installations."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"request install packages"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Allows an application to request installation of packages."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ask to ignore battery optimisations"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Allows an app to ask for permission to ignore battery optimisations for that app."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tap twice for zoom control"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Couldn\'t add widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Go"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Until <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Until <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (next alarm)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Until you turn this off"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Until you turn off Do Not Disturb"</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">"Collapse"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 19d00d0..347a331 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permite que una aplicación lea sesiones de instalación. Esto le permite ver detalles acerca de instalaciones de paquetes activas."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"solicitar la instalación de paquetes"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Permite que una aplicación solicite la instalación de paquetes."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"solicitar permiso para ignorar las optimizaciones de la batería"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Permite que una app solicite permiso para ignorar las optimizaciones de la batería."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Presiona dos veces para obtener el control del zoom"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"No se pudo agregar el widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Ir"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Hasta la(s) <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Hasta la hora <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próxima alarma)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Hasta que lo desactives"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Hasta que desactives No molestar"</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">"Contraer"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 487cf74..0d624c7 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permite que una aplicación consulte sesiones de instalación para ver detalles sobre instalaciones de paquetes activos."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"solicitar instalación de paquetes"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Permite a una aplicación solicitar la instalación de paquetes."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"solicitar permiso para ignorar las optimizaciones de la batería"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Permite que una aplicación solicite permiso para ignorar las optimizaciones de la batería."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Da dos toques para acceder al control de zoom."</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"No se ha podido añadir el widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Ir"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Hasta las <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Hasta las <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próxima alarma)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Hasta desactivar esta opción"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Hasta que desactives la opción No molestar"</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">"Contraer"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 7f46309..a6c6cc9 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Lubab rakendusel lugeda installiseansse. See võimaldab näha aktiivse paketi installimise üksikasju."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"installipakettide taotlemine"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Võimaldab rakendusel pakettide installimist taotleda."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"küsida luba aku optimeerimise eiramiseks"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Lubab rakendusel küsida luba rakenduse aku optimeerimise eiramiseks."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Suumi kasutamiseks koputage kaks korda"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Vidinat ei saanud lisada."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Mine"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Kuni <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Kuni <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (järgmine äratus)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Kuni lülitate selle välja"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Kuni lülitate välja valiku Mitte segada"</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">"Ahendamine"</string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index 2490b21..c2f6d7a 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Instalazio-saioak irakurtzea baimentzen die aplikazioei. Horrela, pakete-instalazio aktiboei buruzko xehetasunak ikus ditzakete."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"Eskatu instalazio-paketeak"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Paketeak instalatzeko eskatzea baimentzen die aplikazioei."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"Eskatu bateriaren optimizazioei ez ikusi egitea"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Bateriaren optimizazioei ez ikusi egiteko baimena eskatzea baimentzen die aplikazioei."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Sakatu birritan zooma kontrolatzeko"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Ezin izan da widgeta gehitu."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Joan"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> arte"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> arte (hurrengo alarma)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Zuk desaktibatu arte"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"\"Ez molestatu\" desaktibatzen duzun arte"</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">"Tolestu"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 63c0d2a..8585bff 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"درخواست نادیده‌گرفتن بهینه‌سازی باتری"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"به یک برنامه اجازه می‌دهد جهت نادیده گرفتن بهینه‌سازی باتری برای خود مجوز درخواست کند."</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"تا <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"تا <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (هشدار بعدی)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"تا وقتی آن را خاموش کنید"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"تا زمانی که «مزاحم نشوید» را خاموش کنید"</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">"کوچک کردن"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 9e9d3d1..4b463109 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Sallii sovelluksen lukea asennusistuntoja. Toiminto sallii sovelluksen lukea aktiivisten asennuspakettien tietoja."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"pyytää asennuspaketteja"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Antaa sovelluksen pyytää pakettien asennusta."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"Lupa ohittaa akun optimoinnit"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Sallii sovelluksen pyytää lupaa ohittaa tietyn sovelluksen akun optimoinnit."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Hallitse zoomausta napauttamalla kahdesti"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Widgetin lisääminen epäonnistui."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Siirry"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Kunnes kello on <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> asti (seuraava hälytys)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Kunnes poistat tämän käytöstä"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Kunnes poistat Varattu-tilan käytöstä."</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">"Kutista"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 15aaf84..d7a1bd6 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permet à une application d\'accéder aux sessions d\'installation. Cela lui permet de consulter les détails relatifs à l\'installation des paquets actifs."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"demander l\'installation de paquets"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Permet à une application de demander l\'installation de paquets."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"demander d\'ignorer les optimisations de la pile"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Permet à une application de demander la permission d\'ignorer les optimisations de la pile."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Appuyer deux fois pour régler le zoom"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Impossible d\'ajouter le widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Aller"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (alarme suivante)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Jusqu\'à la désactivation"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Jusqu\'à ce que vous désactiviez le mode « Ne pas déranger »"</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">"Réduire"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index b8fe1e0..af291d4 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permet à une application d\'accéder aux sessions d\'installation. Cela lui permet de consulter les détails relatifs à l\'installation des packages actifs."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"demander l\'installation de packages"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Permet à une application de demander l\'installation de packages."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"demander à ignorer les optimisations de batterie"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Autorise une application à demander l\'autorisation d\'ignorer les optimisations de batterie pour cette application."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Appuyer deux fois pour régler le zoom"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Impossible d\'ajouter le widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"OK"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (alarme suivante)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Jusqu\'à la désactivation"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Jusqu\'à ce que vous désactiviez la fonctionnalité \"Ne pas déranger\""</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">"Réduire"</string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index b3fbfe8..27acc35 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permite que unha aplicación consulte as sesións de instalación. Desta forma, pode ver os detalles acerca das instalacións de paquetes activas."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"solicitar instalación de paquetes"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Permite a unha aplicación solicitar a instalación dos paquetes."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"pedir que se ignore a optimización da batería"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Fai que unha aplicación poida solicitar permiso para ignorar as optimizacións da batería."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Toca dúas veces para controlar o zoom"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Non se puido engadir o widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Ir"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Ata as <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Ata as <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próxima alarma)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Ata que desactives isto"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Ata que desactives o modo Non molestar"</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">"Contraer"</string>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index d8578c9..a36079f 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"બૅટરી ઓપ્ટિમાઇઝેશન્સને અવગણવા માટે પૂછો"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"ઍપ્લિકેશનને તે ઍપ્લિકેશન માટે બૅટરી ઓપ્ટિમાઇઝેશન્સને અવગણવાની પરવાનગી આપવા માટે પૂછવાની મંજૂરી આપે છે."</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> સુધી"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (આગલા એલાર્મ) સુધી"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"તમે આ બંધ ન કરો ત્યાં સુધી"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"તમે ખલેલ પાડશો નહીં બંધ ન કરો ત્યાં સુધી"</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">"સંકુચિત કરો"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index c2f35f9..f58b293 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"बैटरी ऑप्टिमाइज़ेशन पर ध्यान ना देने के लिए पूछें"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"किसी ऐप्लिकेशन को उस ऐप्लिकेशन के लिए बैटरी ऑप्टिमाइज़ेशन पर ध्यान ना देने की अनुमति के लिए पूछने देता है."</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> तक"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (अगले अलार्म) तक"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"जब तक आप इसे बंद नहीं कर देते"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"जब तक कि आप परेशान ना करें को बंद नहीं कर देते"</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">"संक्षिप्त करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 7106e35..a4fc7c4 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1237,10 +1237,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Omogućuje aplikaciji čitanje sesija instaliranja. Aplikacija može vidjeti pojedinosti o aktivnim instaliranjima paketa."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"zahtijevati instaliranje paketa"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Aplikaciji omogućuje zahtijevanje instaliranja paketa."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"tražiti zanemarivanje optimizacija baterije"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Aplikaciji omogućuje da traži dopuštenje za zanemarivanje optimizacija baterije za tu aplikaciju."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Dvaput dotaknite za upravljanje zumiranjem"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Widget nije moguće dodati."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Idi"</string>
@@ -1651,7 +1649,8 @@
     </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> (sljedeći alarm)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Dok ne isključite"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Dok ne isključite \"Ne uznemiravaj\""</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">"Sažmi"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 6acbcb6..0823d48 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Engedélyezi az alkalmazásnak a telepítési munkamenetek olvasását. Ezáltal részleteket kaphat az egyes csomagok éppen folyamatban lévő telepítéséről."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"telepítőcsomagok kérése"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Lehetővé teszi az alkalmazás számára csomagok telepítésének kérését."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"Akkumulátoroptimalizálási beállítások mellőzésének kérése"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Az alkalmazás engedélyt kérhet az akkumulátoroptimalizálási beállítások mellőzésére."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Érintse meg kétszer a nagyítás beállításához"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Nem sikerült hozzáadni a modult."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Ugrás"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Eddig: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Eddig: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (ez a következő ébresztés)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Amíg ki nem kapcsolja ezt"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Amíg ki nem kapcsolja a „Ne zavarjanak” lehetőséget"</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">"Összecsukás"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 85fb492..0f88ee2 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"հայցել մարտկոցի օպտիմալացումն անտեսելու թույլտվություն"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Հավելվածին հնարավորություն է տալիս հայցելու թույլտվություն՝ տվյալ հավելվածի համար մարտկոցի օպտիմալացումն անտեսելու համար:"</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Մինչև <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Մինչև ժ. <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>-ը (հաջորդ զարթուցիչը)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Քանի դեռ չեք անջատել"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Մինչև չանջատեք «Չանհանգստացնել» գործառույթը"</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">"Թաքցնել"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 343191c..75907a9 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Memungkinkan aplikasi membaca sesi pemasangan. Tindakan ini memungkinkannya melihat detail tentang pemasangan paket aktif."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"minta pasang paket"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Mengizinkan aplikasi meminta pemasangan paket."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"meminta mengabaikan pengoptimalan baterai"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Mengizinkan aplikasi meminta izin untuk mengabaikan pengoptimalan baterai bagi aplikasi tersebut."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Ketuk dua kali untuk kontrol perbesar/perkecil"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Tidak dapat menambahkan widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Buka"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Hingga <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Hingga <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (alarm berikutnya)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Hingga Anda menonaktifkan ini"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Hingga Anda menonaktifkan status Jangan Ganggu"</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">"Ciutkan"</string>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index a875301..4226a86 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Leyfir forriti að lesa uppsetningarlotur. Þetta gerir því kleift að sjá upplýsingar um virkar pakkauppsetningar."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"fara fram á uppsetningu pakka"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Leyfir forriti að fara fram á uppsetningu pakka."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"biðja um að hunsa rafhlöðusparnað"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Gerir forriti kleift að biðja um heimild til að hunsa rafhlöðusparnað fyrir forritið."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Ýttu tvisvar til að opna aðdráttarstýringar"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Ekki tókst að bæta græju við."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Áfram"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Til <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Þangað til <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (næsta viðvörun)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Þar til þú slekkur á þessu"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Þar til þú slekkur á „Ónáðið ekki“"</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">"Minnka"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 7bae091..e54ed19 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Consente a un\'applicazione di leggere le sessioni di installazione. L\'app può conoscere i dettagli sulle installazioni di pacchetti attive."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"richiesta di pacchetti di installazione"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Consente a un\'applicazione di richiedere l\'installazione di pacchetti."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"chiedi di ignorare le ottimizzazioni della batteria"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Consente a un\'app di chiedere l\'autorizzazione a ignorare le ottimizzazioni della batteria per quell\'app."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tocca due volte per il comando dello zoom"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Aggiunta del widget non riuscita."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Vai"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Fino a <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Fino a <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (prossima sveglia)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Fino alla disattivazione"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Fino alla disattivazione di Non disturbare"</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">"Comprimi"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index c79f889..d0d8e06 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1262,10 +1262,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"בקשה להתעלם מאופטימיזציות של הסוללה"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"מאפשר לאפליקציה לבקש רשות להתעלם מאופטימיזציות של הסוללה לאפליקציה הזו."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"הקש פעמיים לבקרת מרחק מתצוגה"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"‏לא ניתן להוסיף widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"התחל"</string>
@@ -1686,7 +1684,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"עד <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"עד <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (ההתראה הבאה)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"עד שתכבה"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"עד שתכבה את \'נא לא להפריע\'"</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">"כווץ"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index f2e927e..cf8052e 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"電池の最適化を無視するかどうかの確認"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"電池の最適化の無視についてアプリが確認することを許可します。"</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>まで"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>(次のアラーム)まで"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"ユーザーがOFFにするまで"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"マナーモードを OFF にするまで"</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">"折りたたむ"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index dfdc182c..2b6ee7f 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ბატარეის ოპტიმიზაციის იგნორირების მოთხოვნა"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"საშუალებას მისცემს აპს, მოითხოვოს მასთან დაკავშირებული ბატარეის ოპტიმიზაციის იგნორირების ნებართვა."</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>-მდე"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>-მდე (შემდეგი მაღვიძარა)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"სანამ ამას გამორთავდეთ"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"სანამ გამორთავთ „არ შემაწუხოთ“ ფუნქციას"</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">"აკეცვა"</string>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index bd4e171..ad9060c 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"батареяны оңтайландыру әрекетін елемеуді сұрау"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Қолданба батареяны оңтайландыру әрекетін елемеуді сұрай алады."</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> дейін"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> дейін (келесі дабыл)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Сіз осыны өшіргенше"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Өшірмейінше мазаламау"</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">"Тасалау"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 49d3a64..e53164a 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -1214,10 +1214,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ស្នើឲ្យមិនអើពើចំពោះការបង្កើនប្រសិទ្ធភាពថ្ម"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"អនុញ្ញាតឲ្យកម្មវិធីស្នើសុំការអនុញ្ញាត ដើម្បីមិនអើពើចំពោះការបង្កើនប្រសិទ្ធភាពថ្ម។"</string>
     <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>
@@ -1618,7 +1616,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"រហូត​ដល់ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"រហូតដល់ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (ម៉ោងរោទិ៍បន្ទាប់)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"រហូត​ដល់ពេល​​អ្នក​បិទ​វា"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"រហូតទាល់តែអ្នកបិទ កុំរំខាន"</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">"បង្រួម"</string>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index bfd69d6..5342672 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ಬ್ಯಾಟರಿ ಆಪ್ಟಿಮೈಸೇಶನ್‌ಗಳನ್ನು ಕಡೆಗಣಿಸಲು ಕೇಳಿ"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"ಈ ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಬ್ಯಾಟರಿ ಆಪ್ಟಿಮೈಸೇಶನ್‌ಗಳನ್ನು ಕಡೆಗಣಿಸುವುದಕ್ಕೆ ಅನುಮತಿಯನ್ನು ಕೇಳಲು ಅಪ್ಲಿಕೇಶನ್‌ ಅನ್ನು ಅನುಮತಿಸುತ್ತದೆ."</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> ವರೆಗೆ"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> ವರೆಗೆ (ಮುಂದಿನ ಅಲಾರಮ್)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"ನೀವಿದನ್ನು ಆಫ್‌ ಮಾಡುವವರೆಗೆ"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"ನೀವು ಆಫ್ ಮಾಡುವವರೆಗೂ ಅಡಚಣೆ ಮಾಡಬೇಡಿ"</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">"ಸಂಕುಚಿಸು"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index e81de03..11f26eb 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -248,9 +248,9 @@
     <string name="permgrouplab_location" msgid="7275582855722310164">"위치"</string>
     <string name="permgroupdesc_location" msgid="1346617465127855033">"이 기기의 위치정보에 액세스"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"캘린더"</string>
-    <string name="permgroupdesc_calendar" msgid="3889615280211184106">"일정에 접근할 수 있도록"</string>
+    <string name="permgroupdesc_calendar" msgid="3889615280211184106">"캘린더에 액세스"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
-    <string name="permgroupdesc_sms" msgid="4656988620100940350">"문자 메시지를 보내고 확인할 수 있도록"</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="permgrouplab_microphone" msgid="171539900250043464">"마이크"</string>
@@ -258,7 +258,7 @@
     <string name="permgrouplab_camera" msgid="4820372495894586615">"카메라"</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="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"창 콘텐츠 가져오기"</string>
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"배터리 최적화를 무시하도록 요청"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"앱에서 배터리 최적화를 무시할 수 있는 권한을 요청할 수 있도록 허용합니다."</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>까지"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>(다음 알람)까지"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"이 기능을 사용 중지할 때까지"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"알림 일시중지 기능을 사용 중지할 때까지"</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">"접기"</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index d4fa9d8..86bcef3 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"батареянын кубатын көп керектей берсин"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Колдонмо батареянын кубатын керектегенден мурун уруксат суралсын."</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> чейин"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> чейин (кийинки ойготкуч)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Бул өчүрүлгөнгө чейин"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"\"Тынчымды алба\" режими өчүрүлгөнгө чейин"</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">"Жыйнап коюу"</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 7e0f79c..9e15571 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ຖາມເພື່ອໃຫ້ເພີກເສີຍການປັບແຕ່ງແບັດເຕີຣີ"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"ອະນຸຍາດໃຫ້ແອັບຖາມສິດອະນຸຍາດເພື່ອເພີກເສີຍຕໍ່ການປັບແຕ່ງແບັດເຕີຣີສຳລັບແອັບນັ້ນ."</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"ຈົນ​ຮອດ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"ຈົນ​ກ​່​ວາ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (ສັນ​ຍານ​ເຕືອນ​ຕໍ່ໄປ​)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"ຈົນກວ່າ​ທ່ານ​ຈະ​ປິດ​"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"ຈົນ​ກ່​ວາ​ທ່ານ​ປິດ​ຫ້າມ​ລົບ​ກວນ"</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">"ຫຍໍ້"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 3100570..3591ea4 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1262,10 +1262,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Leidžiama programai skaityti diegimo seansus. Leidžiama peržiūrėti išsamią aktyvių paketų diegimo informaciją."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"pateikti užklausą dėl diegimo paketų"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Programai leidžiama pateikti užklausą dėl paketų diegimo."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"prašyti nepaisyti akumuliatoriaus optimizavimo nustatymų"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Programai leidžiama prašyti leidimo nepaisyti tai programai skirto akumuliatoriaus optimizavimo nustatymų."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Bakstelėkite du kartus, kad valdytumėte mastelio keitimą"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Nepavyko pridėti."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Pradėti"</string>
@@ -1686,7 +1684,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Iki <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Iki <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (kitas signalas)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Kol išjungsite"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Kol neišjungsite režimo „Netrukdyti“"</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">"Sutraukti"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 5393e49..2f2399b 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1237,10 +1237,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Ļauj lietojumprogrammai lasīt instalēšanas sesijas. Tādējādi lietojumprogrammai ir pieejama informācija par aktīvajām pakotņu instalācijām."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"Pieprasīt pakotņu instalēšanu"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Ļauj lietojumprogrammai pieprasīt pakotņu instalēšanu."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"Lūgt akumulatora optimizācijas ignorēšanu"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Ļauj lietotnei lūgt atļauju ignorēt akumulatora optimizāciju šai lietotnei."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Pieskarieties divreiz, lai kontrolētu tālummaiņu."</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Nevarēja pievienot logrīku."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Doties uz"</string>
@@ -1651,7 +1649,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Līdz <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Līdz plkst. <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (nākamais signāls)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Līdz brīdim, kad izslēgsiet"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Līdz izslēgsiet statusu “Netraucēt”"</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">"Sakļaut"</string>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index f0c9a8d..2a4cd9d 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"прашај дали да се игнорираат оптимизациите на батеријата"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Овозможува апликацијата да побара дозвола за игнорирање на оптимизациите на батеријата за таа апликација."</string>
     <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>
@@ -1618,7 +1616,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (следниот аларм)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Додека не го исклучите"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Додека не го исклучите Не вознемирувај"</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">"Собери"</string>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index a1e7214..0c7eff1 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ബാറ്ററി ഒപ്റ്റിമൈസേഷനുകൾ അവഗണിക്കാൻ ആവശ്യപ്പെടുക"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"ആപ്പിന് വേണ്ടിയുള്ള ബാറ്ററി ഒപ്റ്റിമൈസേഷനുകളെ അവഗണിക്കാനുള്ള അനുമതി ചോദിക്കുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> വരെ"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> വരെ (അടുത്ത അലാറം)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"നിങ്ങൾ ഇത് ഓ‌ഫാക്കും വരെ"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"\'ശല്ല്യപ്പെടുത്തരുത്\' ഓഫാക്കുന്നതുവരെ"</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">"ചുരുക്കുക"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 3f9618c..73a8be0 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"батерейны оновчлол алгасахыг асуух"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Тухайн аппaaс батерейны оновчлол алгасах зөвшөөрөл асуухыг зөвшөөрдөг."</string>
     <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>
@@ -1614,7 +1612,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> хүртэл"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> хүртэл (дараагийн сэрүүлэг)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Таныг унтраах хүртэл"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"\"Бүү саад бол\"-ыг унтраах хүртэл"</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">"Хумих"</string>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index d5487e1..3228337 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"बॅटरी ऑप्टिमायझेशन दुर्लक्षित करण्‍यास सांगा"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"त्या अॅपसाठी बॅटरी ऑप्टिमायझेशन दुर्लक्षित करण्‍यासाठी अॅपला परवानगी मागण्याची अनुमती देते."</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> पर्यंत"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> पर्यंत (पुढील अलार्म)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"आपण हे बंद करेपर्यंत"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"आपण बंद करेपर्यंत व्यत्यय आणू नका"</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">"संक्षिप्त करा"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 1ef6493..bd28553 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Membenarkan aplikasi membaca sesi pemasangan Ini membenarkan apl melihat butiran mengenai pemasangan pakej yang aktif."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"minta pakej pemasangan"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Membenarkan aplikasi meminta pemasangan pakej."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"minta kebenaran untuk mengabaikan pengoptimuman bateri"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Membenarkan apl meminta kebenaran untuk mengabaikan pengoptimuman bateri untuk apl itu."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Ketik dua kali untuk mendapatkan kawalan zum"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Tidak dapat menambahkan widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Pergi"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Sehingga <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Sehingga <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (penggera akan datang)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Sehingga anda matikan"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Hingga anda mematikan Jangan Ganggu"</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">"Runtuhkan"</string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 2117c56..489a85a 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ဘက်ထရီ ပိုမိုကောင်းမွန်အောင် ပြုလုပ်ခြင်းကို လျစ်လျူရှုရန် တောင်းဆိုပါ"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"ဘက်ထရီ ပိုမိုကောင်းမွန်အောင် ပြုလုပ်ခြင်းကို လျစ်လျူရှုရန်အတွက် ခွင့်ပြုချက်တောင်းရန် အက်ပ်ကို ခွင့်ပြုပါ။"</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>အထိ"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> အထိ (လာမည့် နှိုးစက်)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"သင်က ဒါကို ပိတ်မပစ်သည့် အထိ"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"မနှောင့်ယှက်ရန် ကိုသင်ပိတ်သည်အထိ"</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">"ခေါက်ရန်"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index f2b11c9..34909e1 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Tillater en app å lese installeringsøkter. Dette gjør det mulig for den å se detaljer om aktive pakkeinstallasjoner."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"be om installasjon av pakker"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Lar apper be om installasjon av pakker."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"be om å ignorere batterioptimaliseringer"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Gjør det mulig for apper å be om tillatelse til å ignorere batterioptimaliseringer for disse appene."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Trykk to ganger for zoomkontroll"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Kunne ikke legge til modulen."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Utfør"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Til <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Til <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (neste alarm)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Inntil du slår av funksjonen"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Inntil du slår av Ikke forstyrr"</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">"Skjul"</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 15f787937..5df851f 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -1218,10 +1218,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ब्याट्री सम्बन्धी अनुकूलनहरूलाई बेवास्ता गर्न सोध्नुहोस्"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"कुनै अनुप्रयोगलाई त्यसका ब्याट्री सम्बन्धी अनुकूलनहरूलाई बेवास्ता गर्नका लागि अनुमति माग्न दिन्छ।"</string>
     <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>
@@ -1622,7 +1620,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> सम्म"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (अर्को अलार्म) सम्म"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"तपाईँले यसलाई बन्द नगरेसम्म"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"तपाईँले बन्द नगरे सम्म बाधा नपुर्याउँनुहोस्"</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">"संक्षिप्त पार्नुहोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 9112a8c..caa8058 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Hiermee wordt een app toegestaan installatiesessies te lezen. Zo kan de app informatie bekijken over actieve pakketinstallaties."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"installatiepakketten aanvragen"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Hiermee kan een app installatie van pakketten aanvragen."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"vragen om batterijoptimalisatie te negeren"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Hiermee kan een app toestemming vragen om batterijoptimalisatie voor die app te negeren."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tik twee keer voor zoomregeling"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Kan widget niet toevoegen."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Ga"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Tot <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Tot <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (volgend alarm)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Totdat u dit uitschakelt"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Totdat u \'Niet storen\' uitschakelt"</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">"Samenvouwen"</string>
diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
index a3628cc..e88aa87 100644
--- a/core/res/res/values-pa-rIN/strings.xml
+++ b/core/res/res/values-pa-rIN/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ਬੈਟਰੀ ਸੁਯੋਗਤਾਵਾਂ ਨੂੰ ਅਣਡਿੱਠ ਕਰਨ ਲਈ ਪੁੱਛੋ"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"ਕਿਸੇ ਐਪ ਨੂੰ ਉਸ ਵਾਸਤੇ ਬੈਟਰੀ ਸੁਯੋਗਤਾਵਾਂ ਨੂੰ ਅਣਡਿੱਠ ਕਰਨ ਲਈ ਇਜਾਜ਼ਤ ਵਾਸਤੇ ਪੁੱਛਣ ਲਈ ਆਗਿਆ ਦਿੰਦੀ ਹੈ।"</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> ਤੱਕ"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> ਤੱਕ (ਅਗਲਾ ਅਲਾਰਮ)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਇਸਨੂੰ ਬੰਦ ਨਹੀਂ ਕਰਦੇ ਹੋ"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ ਨੂੰ ਬੰਦ ਨਹੀਂ ਕਰਦੇ ਹੋ"</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">"ਨਸ਼ਟ ਕਰੋ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index bdd601a..13ea8d3 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1262,10 +1262,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Pozwala aplikacji odczytywać sesje instalacji. Umożliwia to jej na poznanie szczegółów aktywnych instalacji pakietów."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"żądanie instalacji pakietów"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Zezwala aplikacji żądanie instalacji pakietów."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"Prośba o ignorowanie optymalizacji wykorzystania baterii"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Zezwala aplikacji na proszenie o uprawnienia do ignorowania optymalizacji wykorzystania baterii w przypadku danej aplikacji."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Dotknij dwukrotnie, aby sterować powiększeniem"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Nie można dodać widżetu."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"OK"</string>
@@ -1686,7 +1684,8 @@
     </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> (następny alarm)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Dopóki nie wyłączysz"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Do wyłączenia Nie przeszkadzać"</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">"Zwiń"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 40bb94a..c0d53f2 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permite que um app leia sessões de instalação. Isso permite que ele veja detalhes sobre as instalações de pacote ativas."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"solicitar pacotes de instalação"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Permite que um app solicite a instalação de pacotes."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"solicitar que as otimizações de bateria sejam ignoradas"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Permite que um app peça permissão para ignorar as otimizações de bateria para esse app."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Toque duas vezes para ter controle do zoom"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Não foi possível adicionar widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Ir"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próximo alarme)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Até você desativar"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Até que você desative \"Não perturbe\""</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">"Recolher"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 6fdaa19..f6dcb87 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permite que uma aplicação leia sessões de instalação. Isto permite que veja detalhes acerca de instalações de pacotes ativas."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"solicitar pacotes de instalação"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Permite que uma aplicação solicite a instalação de pacotes."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"pedir para ignorar as otimizações da bateria"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Permite que uma aplicação solicite autorização para ignorar as otimizações da bateria para a mesma."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tocar duas vezes para controlar o zoom"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Não foi possível adicionar widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Ir"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próximo alarme)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Até que o utilizador desative"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Até desativar Não incomodar"</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">"Reduzir"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 40bb94a..c0d53f2 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permite que um app leia sessões de instalação. Isso permite que ele veja detalhes sobre as instalações de pacote ativas."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"solicitar pacotes de instalação"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Permite que um app solicite a instalação de pacotes."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"solicitar que as otimizações de bateria sejam ignoradas"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Permite que um app peça permissão para ignorar as otimizações de bateria para esse app."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Toque duas vezes para ter controle do zoom"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Não foi possível adicionar widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Ir"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próximo alarme)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Até você desativar"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Até que você desative \"Não perturbe\""</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">"Recolher"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index e732022..05025c3 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1237,10 +1237,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permite unei aplicații accesul la citirea sesiunilor de instalare. Aceasta poate vedea detalii despre instalările de pachete active."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"să solicite pachete de instalare"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Permite unei aplicații să solicite instalarea pachetelor."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"să solicite ignorarea optimizărilor bateriei"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Permite unei aplicații să solicite permisiunea de a ignora optimizările bateriei pentru aplicația respectivă."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Apăsați de două ori pentru a controla mărirea/micșorarea"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Nu s-a putut adăuga widgetul."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Accesați"</string>
@@ -1651,7 +1649,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Până la <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Până la <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (următoarea alarmă)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Până la dezactivare"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Până când dezactivați „Nu deranja”"</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">"Restrângeți"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 9c45d89..f83a878 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1262,10 +1262,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"Без ограничения расхода батареи"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Разрешает приложению игнорировать ограничение на расход заряда батареи."</string>
     <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>
@@ -1686,7 +1684,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (будильник)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Пока я не отключу"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Пока вы не отключите режим \"Не беспокоить\""</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">"Свернуть"</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 87a277b..5911e5e 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -269,8 +269,8 @@
     <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"යෙදුම් අන්තර්ගතයට ප්‍රවේශ්‍යතාවය වැඩිවන ලෙස සකස් කිරීමට ඇතැම් විට ස්ක්‍රිප්ට් ස්ථාපනය කර ඇත."</string>
     <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"ඔබ ටයිප් කළ පෙළ බලන්න"</string>
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"ණයවරපත් අංක සහ මුරපද වැනි පුද්ගලික දත්ත ඇතුළත් වේ."</string>
-    <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"සංදර්ශන විශාලන මට්ටම පාලනය කිරීම"</string>
-    <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"සංදර්ශනයේ විශාලන මට්ටම සහ පිහිටීම පාලනය කිරීම."</string>
+    <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"සංදර්ශනයේ විශාලනය පාලනය කරන්න"</string>
+    <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"සංදර්ශනයේ විශාලන මට්ටම සහ පිහිටීම පාලනය කරන්න."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"අභින සිදු කරන්න"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"තට්ටු කිරීමට, ස්වයිප් කිරීමට, පින්ච් කිරීමට, සහ වෙනත් අභින සිදු කිරීමට හැකිය."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"තත්ව තීරුව අබල කරන්න හෝ වෙනස් කරන්න"</string>
@@ -459,13 +459,13 @@
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"සමමුහුර්ත සැකසීම් කියවන්න"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ගිණුම සඳහා සමමුහුර්ත සැකසීම් කියවීමට යෙදුමට අවසර දෙන්න. උදාහරණයක් ලෙස, ගිණුමක් සමඟ පුද්ගල යෙදුම සමමුහුර්ත දැයි මෙයට හඳුනා ගත හැක."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"සමමුහුර්ත කිරීම සක්‍රිය කරන්න සහ අක්‍රිය කරන්න"</string>
-    <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"ගිණුම සඳහා සමමුහුර්ත සැකසීම් වෙනස් කිරීමට යෙදුමට අවසර දෙන්න. උදාහරණයක් ලෙස, ගිණුම සමඟ පුද්ගල යෙදුම සමමුහුර්ත කිරීම සක්‍රිය කිරීමට භාවිත කල හැක."</string>
+    <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"ගිණුමක් සඳහා සමමුහුර්ත සැකසීම් විකරණය කිරීමට යෙදුමකට ඉඩ දෙයි. උදාහරණයක් ලෙස, ගිණුමක් සමඟ පුද්ගල යෙදුම සමමුහුර්ත කිරීම සබල කිරීමට මෙය භාවිත කළ හැක."</string>
     <string name="permlab_readSyncStats" msgid="7396577451360202448">"සමමුහුර්ත කිරීමේ සංඛ්‍යාන කියවීම"</string>
     <string name="permdesc_readSyncStats" msgid="1510143761757606156">"සමමුහුර්ත කිරීමේ සිදුවීම් ඉතිහාසය සහ කෙතරම් දත්ත සමමුහුර්ත වී ඇතිදැයි ඇතුලත් ගිණුම සඳහා සමමුහුර්ත කිරීමේ සංඛ්‍යාන කියවීමට යෙදුමට අවසර දෙන්න."</string>
     <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"ඔබගේ USB ආචයනය හි අන්තර්ගතය කියවන්න"</string>
     <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"ඔබගේ SD කාඩ් පතෙහි අන්තර්ගතය කියවන්න"</string>
     <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"යෙදුමට ඔබගේ USB ආචයනය අන්තර්ගතය කියවීමට අවසර දෙන්න."</string>
-    <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"යෙදුමට ඔබගේ SD කාඩ් පතින් අන්තර්ගත කියවීමට අවසර දෙන්න."</string>
+    <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"යෙදුමට ඔබගේ SD කාඩ්පතේ අන්තර්ගතය කියවීමට ඉඩ දෙයි."</string>
     <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"ඔබගේ USB ආචයනයේ අන්තර්ගත වෙනස් කිරීම හෝ මැකීම"</string>
     <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"ඔබගේ SD පතේ අන්තර්ගත වෙනස් කිරීම හෝ මැකීම"</string>
     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"USB ආචයනය වෙත ලිවීමට යෙදුමට අවසර දෙන්න."</string>
@@ -739,7 +739,7 @@
     <!-- String.format failed for translation -->
     <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
     <skip />
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"විජටය එකතු කරන්න."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"විජටය එක් කරන්න."</string>
     <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"හිස්"</string>
     <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"අගුළු අරින ප්‍රදේශය විදහා ඇත."</string>
     <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"අගුළු අරින ප්‍රදේශය හැකිලී ඇත."</string>
@@ -952,7 +952,7 @@
     <string name="undo" msgid="7905788502491742328">"අස් කරන්න"</string>
     <string name="redo" msgid="7759464876566803888">"යළි කරන්න"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"පෙළ තේරීම"</string>
-    <string name="addToDictionary" msgid="4352161534510057874">"ශබ්ද කෝෂයට එකතු කරන්න"</string>
+    <string name="addToDictionary" msgid="4352161534510057874">"ශබ්ද කෝෂයට එක් කරන්න"</string>
     <string name="deleteText" msgid="6979668428458199034">"මකන්න"</string>
     <string name="inputMethod" msgid="1653630062304567879">"ආදාන ක්‍රමය"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"පෙළ ක්‍රියාවන්"</string>
@@ -1214,10 +1214,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"බැටරි ප්‍රශස්තකරණ නොසලකා හැරීමට ඉල්ලන්න"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"යෙදුමකට එම යෙදුම සඳහා බැටරි ප්‍රශස්තකරණ නොසලකා හැරීමට අවසර ඉල්ලීමට ඉඩ දෙයි."</string>
     <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>
@@ -1292,7 +1290,7 @@
     <string name="sync_undo_deletes" msgid="2941317360600338602">"මැකීම් අස් කරන්න"</string>
     <string name="sync_do_nothing" msgid="3743764740430821845">"දැනට කිසිවක් නොකරන්න"</string>
     <string name="choose_account_label" msgid="5655203089746423927">"ගිණුමක් තෝරන්න"</string>
-    <string name="add_account_label" msgid="2935267344849993553">"ගිණුමක් එකතු කරන්න"</string>
+    <string name="add_account_label" msgid="2935267344849993553">"ගිණුමක් එක් කරන්න"</string>
     <string name="add_account_button_label" msgid="3611982894853435874">"ගිණුමක් එක් කරන්න"</string>
     <string name="number_picker_increment_button" msgid="2412072272832284313">"වැඩි කරන්න"</string>
     <string name="number_picker_decrement_button" msgid="476050778386779067">"අඩු කරන්න"</string>
@@ -1618,7 +1616,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> තෙක්"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> තෙක් (ඊළඟ එලාමය)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"ඔබ මෙය ක්‍රියාවිරහිත කරන තුරු"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"බාධා නොකරන්න ඔබ අක්‍රිය කරන තුරු"</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">"හකුළන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 7811a46..9a41b07 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1262,10 +1262,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Toto povolenie umožňuje aplikácii čítať relácie inštalácií a zobraziť tak podrobnosti o aktívnych inštaláciách balíkov."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"odosielanie žiadostí o inštaláciu balíkov"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Umožňuje aplikácii vyžiadať inštaláciu balíkov."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"požiadať o ignorovanie optimalizácií výdrže batérie"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Umožňuje aplikácii požiadať o povolenie ignorovať optimalizácie výdrže batérie pre danú aplikáciu."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Dvojitým klepnutím môžete ovládať priblíženie"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Miniaplikáciu sa nepodarilo pridať."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Hľadať"</string>
@@ -1686,7 +1684,8 @@
     </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">"Kým túto funkciu nevypnete"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <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>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 5cdbefb..e6b08e9 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1262,10 +1262,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Aplikaciji omogoča branje sej namestitev. Tako lahko bere podrobnosti o aktivnih namestitvah paketov."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"zahtevanje paketov za namestitev"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Aplikaciji omogoča zahtevanje namestitve paketov."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"Dovoljenje za prezrtje optimizacij akumulatorja"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Aplikaciji dovoljuje, da vpraša za dovoljenje, ali naj prezre optimizacije akumulatorja."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tapnite dvakrat za nadzor povečave/pomanjšave"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Pripomočka ni bilo mogoče dodati."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Pojdi"</string>
@@ -1686,7 +1684,8 @@
     </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> (naslednji alarm)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Dokler tega ne izklopite"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Dokler ne izklopite načina »ne moti«"</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">"Strni"</string>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index ea33fff..688d14b 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Lejon një aplikacion të lexojë sesionet e instalimit. Kjo e lejon atë të shohë detaje rreth instalimeve të paketave aktive."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"kërko paketat e instalimit"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Lejon që një aplikacion të kërkojë instalimin e paketave."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"kërko të shpërfillësh optimizimet e baterisë"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Lejon që një aplikacion të kërkojë leje për të shpërfillur optimizimet e baterisë për atë aplikacion."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Trokit dy herë për të kontrolluar zmadhimin"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Nuk mundi të shtonte miniaplikacion."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Shko"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Deri në <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Deri në <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (alarmi tjetër)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Deri sa ta çaktivizosh këtë"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Deri sa të çaktivizosh gjendjen \"Mos shqetëso\""</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">"Shpalos"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 19a1140..1ab6bb3 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1237,10 +1237,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"тражење дозволе за игнорисање оптимизација батерије"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Дозвољава апликацији да тражи дозволу за игнорисање оптимизација батерије за ту апликацију."</string>
     <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>
@@ -1651,7 +1649,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (следећи аларм)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Док не искључите"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Док не искључите режим Не узнемиравај"</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">"Скупи"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 3a4fee3..b4d7f27 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Tillåt appen att läsa installationssessioner. Det ger den tillgång till uppgifter om aktiva paketinstallationer."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"begära installationspaket"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Tillåter att en app begär paketinstallation."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"får be om tillstånd att ignorera batterioptimering"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Appen får be om tillstånd att ignorera batterioptimering."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Peka två gånger för zoomkontroll"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Det gick inte att lägga till widgeten."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Kör"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Till kl. <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Till <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (nästa alarm)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Tills du inaktiverar detta"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Tills du inaktiverar Stör ej"</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">"Komprimera"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 4b75ff1..5183c87 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1210,10 +1210,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Huruhusu programu kusoma vipindi vya kusanikisha. Hii huiruhusu kuona maelezo kuhusu usanikishaji wa programu unaoendelea."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"omba ruhusa ya kusakinisha vifurushi"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Huruhusu programu kuomba idhini ya kusakinisha vifurushi."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"omba kupuuza uimarishji wa betri"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Huruhusu programu kuomba ruhusa ya kupuuza uimarishaji wa betri katika programu yako."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Gonga mara mbili kwa udhibiti wa kuza"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Haikuweza kuongeza wijeti."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Nenda"</string>
@@ -1614,7 +1612,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Hadi <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Mpaka <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (kengele inayofuata)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Hadi utakapozima hili"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Hadi utakapozima Usinisumbue"</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">"Kunja"</string>
diff --git a/core/res/res/values-sw900dp/dimens.xml b/core/res/res/values-sw900dp/dimens.xml
new file mode 100644
index 0000000..11092b2
--- /dev/null
+++ b/core/res/res/values-sw900dp/dimens.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.
+*/
+-->
+<resources>
+
+    <!-- Height of the bottom navigation / system bar. -->
+    <dimen name="navigation_bar_height">56dp</dimen>
+
+    <!-- Height of the bottom navigation bar in landscape; often
+         the same as @dimen/navigation_bar_height -->
+    <dimen name="navigation_bar_height_landscape">56dp</dimen>
+
+</resources>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index 6a54f82..1dfcfb2 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"பேட்டரி மேம்படுத்தல்களைப் புறக்கணிப்பதற்கான அனுமதியைக் கோரு"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"பயன்பாட்டிற்கான பேட்டரி மேம்படுத்தல்களைப் புறக்கணிப்பதற்கான அனுமதியைக் கோர, பயன்பாட்டை அனுமதிக்கும்."</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> வரை"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> மணி (அடுத்த அலாரம்) வரை"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"இதை முடக்கும்வரை"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"தொந்தரவு செய்ய வேண்டாம் என்பதை முடக்கும் வரை"</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">"சுருக்கு"</string>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 49b509c..9a3bfb1 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"బ్యాటరీ అనుకూలీకరణలను విస్మరించడానికి అడగాలి"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"ఆ అనువర్తనం కోసం బ్యాటరీ అనుకూలీకరణలు విస్మరించేలా అనుమతి కోరడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> వరకు"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (తదుపరి అలారం) వరకు"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"మీరు దీన్ని ఆఫ్ చేసే వరకు"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"మీరు అంతరాయం కలిగించవద్దు ఎంపిక ఆఫ్ చేసే వరకు"</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">"కుదించండి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index c4d72ab..25fd417 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ขอเพิกเฉยต่อการเพิ่มประสิทธิภาพแบตเตอรี่"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"อนุญาตให้แอปขอสิทธิ์เพิกเฉยต่อการเพิ่มประสิทธิภาพแบตเตอรี่สำหรับแอปนั้น"</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"จนถึงเวลา <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"จนถึงเวลา <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (การปลุกครั้งถัดไป)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"จนกว่าคุณจะปิดฟังก์ชันนี้"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"จนกว่าคุณจะปิดห้ามรบกวน"</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">"ยุบ"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index a4e1b26..51d22f3 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Pinapayagan ang isang application na magbasa ng mga session ng pag-install. Nagbibigay-daan ito upang makita ang mga detalye tungkol sa mga aktibong pag-install ng package."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"humiling ng mga package sa pag-install"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Pinapayagan ang isang application na hilingin ang pag-install ng mga package."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"hilingin na balewalain ang mga pag-optimize ng baterya"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Pinapayagang humingi ng pahintulot ang isang app na balewalain ang mga pag-optimize ng baterya para sa app na iyon."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tapikin ng dalawang beses para sa pagkontrol ng zoom"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Hindi maidagdag ang widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Pumunta"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Hanggang <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Hanggang <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (susunod na alarm)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Hanggang sa i-off mo ito"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Hanggang sa i-off mo ang Huwag Istorbohin"</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">"I-collapse"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index eacf16e..86b2ab6 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Bir uygulamanın yükleme oturumlarını okumasına izin verir. Bu, etkin paket yüklemeleriyle ilgili ayrıntıların görülmesine olanak tanır."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"paket yükleme isteğinde bulunma"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Uygulamaya, paketleri yükleme isteğinde bulunma izni verir."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"pil optimizasyonlarını göz ardı etme izni iste"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Bir uygulamanın, kendisi için pil optimizasyonlarını göz ardı etme izni istemesine olanak sağlar."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Zum denetimi için iki kez dokun"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Widget eklenemedi."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Git"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Şu saate kadar: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (sonraki alarma) saatine kadar"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Siz bunu kapatana kadar"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Rahatsız Etmeyin ayarını kapatana kadar"</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">"Daralt"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 4dbeb0d..ce55856 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1262,10 +1262,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"запитувати дозвіл ігнорувати оптимізацію використання заряду акумулятора"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Додаток зможе запитувати дозвіл ігнорувати оптимізацію використання заряду акумулятора."</string>
     <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>
@@ -1686,7 +1684,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (наступний будильник)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Доки ви не вимкнете"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Доки ввімкнено режим \"Не турбувати\""</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">"Згорнути"</string>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index 82253ac..c71617a 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"بیٹری کی بہتریاں نظر انداز کرنے کا پوچھیں"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"اس ایپ کیلئے ایک ایپ کو بیٹری کی کارکردگی  بہتر بنانے کو نظر انداز کرنے کی اجازت دیں۔"</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> تک"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> تک (اگلا الارم)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"جب تک آپ اسے آف نہ کر دیں"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"جب تک آپ ڈسڑب نہ کریں کو آف نہیں کر دیتے"</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">"سکیڑیں"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index f44a6c9..b3a248d 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Ilovaga o‘rnatilgan seanslarni o‘qish uchun ruxsat beradi. Bu unga faol paket o‘rnatmalari haqidagi ma’lumotlarni ko‘rish imkonini beradi."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"paketlarni o‘rnatish so‘rovini yuborish"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Ilovaga paketlarni o‘rnatish so‘rovini yuborish imkonini beradi."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"batareya quvvatidan xohlagancha foydalanishni so‘rash"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Ilovaga batareya quvvatidan xohlagancha foydalanish uchun ruxsat so‘rashga imkon beradi."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Ko‘lamini o‘zgartirish uchun ikki marta bosing"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Vidjet qo‘shilmadi."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"O‘tish"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> gacha"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> gacha (keyingi signal)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Men o‘chirmaguncha"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"“Bezovta qilinmasin” rejimi o‘chirilmaguncha"</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">"Yig‘ish"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 21ad11c4..8c76073 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Cho phép ứng dụng đọc phiên cài đặt. Thao tác này sẽ cho phép ứng dụng xem chi tiết về gói cài đặt đang hoạt động."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"yêu cầu gói cài đặt"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Cho phép ứng dụng yêu cầu cài đặt gói."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"hỏi để bỏ qua tối ưu hóa pin"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Cho phép ứng dụng hỏi quyền để bỏ qua tối ưu hóa pin cho ứng dụng đó."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Nhấn hai lần để kiểm soát thu phóng"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Không thể thêm tiện ích."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Đến"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Cho đến <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Cho tới <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (cảnh báo tiếp theo)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Cho đến khi bạn tắt tính năng này"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Cho đến khi bạn tắt Đừng làm phiền"</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">"Thu gọn"</string>
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index d13d154..ac7b236 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -65,4 +65,5 @@
 
     <!-- The small screens of watch devices makes multi-window support undesireable. -->
     <bool name="config_supportsMultiWindow">false</bool>
+    <bool name="config_supportsSplitScreenMultiWindow">false</bool>
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 68fec51..1534e30 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"请求忽略电池优化"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"允许应用请求相应的权限,以便忽略针对该应用的电池优化。"</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"到<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"直到<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>(闹钟下次响铃时)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"直到您将其关闭"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"直到您关闭“勿扰”模式"</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">"收起"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index d6b4cf7..57e901d 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"要求忽略電池優化"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"允許應用程式要求就該應用程式忽略電池優化。"</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"完成時間:<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"直至<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (下一次響鬧)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"直至您關閉這項設定"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"直至您關閉「請勿騷擾」功能"</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">"收合"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 74b149d..d3bbf67 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1212,10 +1212,8 @@
     <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 permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"要求忽略電池效能最佳化設定"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"允許應用程式要求權限,以便忽略針對該應用程式的電池效能最佳化設定。"</string>
     <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>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"結束時間:<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"到<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> 為止 (下一個鬧鐘)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"手動關閉這項設定前一律啟用"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"直到您關閉「零打擾」模式"</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">"收合"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index d36b7fb..455dc24 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1212,10 +1212,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Ivumela uhlelo lokusebenza ukufunda izikhathi. Lokhu kuzolivumela ukubona imininingwane mayelana nokufaka kwephakethi esebenzayo."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"cela amaphakheji wokufaka"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Ivumela uhlelo lokusebenza ukucela ukufakwa kwamaphakheji."</string>
-    <!-- no translation found for permlab_requestIgnoreBatteryOptimizations (8021256345643918264) -->
-    <skip />
-    <!-- no translation found for permdesc_requestIgnoreBatteryOptimizations (8359147856007447638) -->
-    <skip />
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"cela ukuziba ukulungiselelwa kwebhethri"</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Ivumela uhlelo lokusebenza ukuthi licele imvume yokuziba ukulungiselela ibhethri yalolo hlelo lokusebenza."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Thepha kabili ukuthola ukulawula ukusondeza"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Yehlulekile ukwengeza i-widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Iya"</string>
@@ -1616,7 +1614,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Kuze kube ngu-<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Kuze kube ngu-<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (i-alamu elandelayo)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Uze uvale lokhu"</string>
+    <!-- no translation found for zen_mode_forever (1916263162129197274) -->
+    <skip />
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Uze uvale ungaphazamisi"</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">"Goqa"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 8c64484..aa050de 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2887,6 +2887,28 @@
         <!-- Defines text displayed in a small popup window on hover or long press. -->
         <attr name="tooltip" format="string" localization="suggested" />
 
+        <!-- Whether this view is a root of a keyboard navigation cluster.
+             See {@link android.view.View#setKeyboardNavigationCluster(boolean)}. -->
+        <attr name="keyboardNavigationCluster" format="boolean" />
+
+        <!-- Whether this view is a root of a keyboard navigation section.
+             See {@link android.view.View#setKeyboardNavigationSection(boolean)}. -->
+        <attr name="keyboardNavigationSection" format="boolean" />
+
+        <!-- Defines the next keyboard navigation cluster.
+
+             If the reference refers to a view that does not exist or is part
+             of a hierarchy that is invisible, a {@link java.lang.RuntimeException}
+             will result when the reference is accessed.-->
+        <attr name="nextClusterForward" format="reference"/>
+
+        <!-- Defines the next keyboard navigation section.
+
+             If the reference refers to a view that does not exist or is part
+             of a hierarchy that is invisible, a {@link java.lang.RuntimeException}
+             will result when the reference is accessed.-->
+        <attr name="nextSectionForward" format="reference"/>
+
     </declare-styleable>
 
     <!-- Attributes that can be assigned to a tag for a particular View. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9e75ff9..5967c69 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1267,7 +1267,8 @@
          This may be empty if network scoring and recommending isn't supported.
          -->
     <string-array name="config_networkRecommendationPackageNames" translatable="false">
-        <!-- Add packages here -->
+        <!-- The standard AOSP network recommendation provider -->
+        <item>com.android.networkrecommendation</item>
     </string-array>
 
     <!-- Whether to enable Hardware FLP overlay which allows Hardware FLP to be
@@ -2568,6 +2569,9 @@
          E.g. freeform, split-screen, picture-in-picture. -->
     <bool name="config_supportsMultiWindow">true</bool>
 
+    <!-- True if the device supports split screen as a form of multi-window. -->
+    <bool name="config_supportsSplitScreenMultiWindow">true</bool>
+
     <!-- True if the device requires AppWidgetService even if it does not have
          the PackageManager.FEATURE_APP_WIDGETS feature -->
     <bool name="config_enableAppWidgetService">false</bool>
@@ -2610,6 +2614,9 @@
     <!-- Component that is the default launcher when demo mode is enabled. -->
     <string name="config_demoModeLauncherComponent">com.android.retaildemo/.DemoPlayer</string>
 
+    <!-- Hashed password (SHA-256) used to restrict demo mode operation -->
+    <string name="config_demoModePassword" translatable="false"></string>
+
     <!-- Flag indicating whether round icons should be parsed from the application manifest. -->
     <bool name="config_useRoundIcon">false</bool>
 
@@ -2687,4 +2694,7 @@
          user-set value if toggled by settings so the "Transition animation scale" setting
          should also be hidden if intended to be permanent. -->
     <item name="config_appTransitionAnimationDurationScaleDefault" format="float" type="dimen">1.0</item>
+
+    <!-- Flag indicates that whether non-system apps can be installed on internal storage. -->
+    <bool name="config_allow3rdPartyAppOnInternal">true</bool>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 37c4fd1..4604f3f 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2776,6 +2776,10 @@
         <public name="paddingHorizontal" />
         <public name="paddingVertical" />
         <public name="visibleToEphemeral" />
+        <public name="keyboardNavigationCluster" />
+        <public name="keyboardNavigationSection" />
+        <public name="nextClusterForward" />
+        <public name="nextSectionForward" />
     </public-group>
 
     <public-group type="style" first-id="0x010302e0">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 87f38c1..510e6af 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -103,6 +103,8 @@
     <!-- Displayed when the user dialed an MMI code whose function
          could not be performed because FDN is enabled. This will be displayed in a toast. -->
     <string name="mmiFdnError">Operation is restricted to fixed dialing numbers only.</string>
+    <!-- Displayed when a carrier does not support call forwarding queries when roaming. -->
+    <string name="mmiErrorWhileRoaming">Can not change call forwarding settings from your phone while you are roaming.</string>
 
     <!-- Displayed when a phone feature such as call barring was activated. -->
     <string name="serviceEnabled">Service was enabled.</string>
@@ -204,6 +206,12 @@
     <!-- Displayed to tell the user that all service is blocked by access control. -->
     <string name="RestrictedOnAll">All voice/data/SMS services are blocked.</string>
 
+    <!-- Displayed to tell the user that they should switch their network preference. -->
+    <string name="NetworkPreferenceSwitchTitle">Can\u2019t reach network</string>
+    <!-- Displayed to tell the user that they should switch their network preference. -->
+    <string name="NetworkPreferenceSwitchSummary">To improve reception, try changing the type selected at Settings > Cellular networks > Preferred network type."</string>
+
+
     <!-- Displayed to tell the user that peer changed TTY mode -->
     <string name="peerTtyModeFull">Peer requested TTY Mode FULL</string>
     <string name="peerTtyModeHco">Peer requested TTY Mode HCO</string>
@@ -741,17 +749,11 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readSms">read your text messages (SMS or MMS)</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readSms" product="tablet">Allows the app to read SMS
-      messages stored on your tablet or SIM card. This allows the app to read all
-      SMS messages, regardless of content or confidentiality.</string>
+    <string name="permdesc_readSms" product="tablet">This app can read all SMS (text) messages stored on your tablet.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readSms" product="tv">Allows the app to read SMS
-      messages stored on your TV or SIM card. This allows the app to read all
-      SMS messages, regardless of content or confidentiality.</string>
+    <string name="permdesc_readSms" product="tv">This app can read all SMS (text) messages stored on your TV.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readSms" product="default">Allows the app to read SMS
-      messages stored on your phone or SIM card. This allows the app to read all
-      SMS messages, regardless of content or confidentiality.</string>
+    <string name="permdesc_readSms" product="default">This app can read all SMS (text) messages stored on your phone.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_receiveWapPush">receive text messages (WAP)</string>
@@ -793,12 +795,9 @@
       running.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_systemAlertWindow">draw over other apps</string>
+    <string name="permlab_systemAlertWindow">This app can appear on top of other apps</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_systemAlertWindow">Allows the app to draw on top of other
-        applications or parts of the user interface.  They may interfere with your
-        use of the interface in any application, or change what you think you are
-        seeing in other applications.</string>
+    <string name="permdesc_systemAlertWindow">This app can appear on top of other apps or other parts of the screen. This may interfere with normal app usage and change the way that other apps appear.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_persistentActivity">make app always run</string>
@@ -904,20 +903,7 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readCallLog">read call log</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readCallLog" product="tablet">Allows the app to read
-     your tablet\'s call log, including data about incoming and outgoing calls.
-     This permission allows apps to save your call log data, and malicious apps
-     may share call log data without your knowledge.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readCallLog" product="tv">Allows the app to read
-     your TV\'s call log, including data about incoming and outgoing calls.
-     This permission allows apps to save your call log data, and malicious apps
-     may share call log data without your knowledge.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readCallLog" product="default">Allows the app to read
-      your phone\'s call log, including data about incoming and outgoing calls.
-      This permission allows apps to save your call log data, and malicious apps
-      may share call log data without your knowledge.</string>
+    <string name="permdesc_readCallLog">This app can read your call history.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_writeCallLog">write call log</string>
@@ -939,46 +925,24 @@
     that monitor your physical condition, such as your heart rate.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_readCalendar">read calendar events plus confidential information</string>
+    <string name="permlab_readCalendar">Read calendar events and details</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readCalendar" product="tablet">Allows the app to read
-       all calendar events stored on your tablet, including those of friends or
-       co-workers. This may allow the app to share or save your calendar data,
-       regardless of confidentiality or sensitivity.</string>
+    <string name="permdesc_readCalendar" product="tablet">This app can read all calendar events stored on your tablet and share or save your calendar data.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readCalendar" product="tv">Allows the app to read
-       all calendar events stored on your TV, including those of friends or
-       co-workers. This may allow the app to share or save your calendar data,
-       regardless of confidentiality or sensitivity.</string>
+    <string name="permdesc_readCalendar" product="tv">This app can read all calendar events stored on your TV and share or save your calendar data.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readCalendar" product="default">Allows the app to
-       read all calendar events stored on your phone, including those of friends
-       or co-workers. This may allow the app to share or save your calendar data,
-       regardless of confidentiality or sensitivity.</string>
+    <string name="permdesc_readCalendar" product="default">This app can read all calendar events stored on your phone and share or save your calendar data.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_writeCalendar">add or modify calendar events and send email to guests without owners\' knowledge</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_writeCalendar" product="tablet">Allows the app to
-        add, remove, change events that you can modify on your tablet, including
-        those of friends or co-workers. This may allow the app to send messages
-        that appear to come from calendar owners, or modify events without the
-        owners\' knowledge.</string>
+    <string name="permdesc_writeCalendar" product="tablet">This app can add, remove, or change calendar events on your tablet. This app can send messages that may appear to come from calendar owners, or change events without notifying their owners.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_writeCalendar" product="tv">Allows the app to
-        add, remove, change events that you can modify on your TV, including
-        those of friends or co-workers. This may allow the app to send messages
-        that appear to come from calendar owners, or modify events without the
-        owners\' knowledge.</string>
+    <string name="permdesc_writeCalendar" product="tv">This app can add, remove, or change calendar events on your TV. This app can send messages that may appear to come from calendar owners, or change events without notifying their owners.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_writeCalendar" product="default">Allows the app to
-        add, remove, change events that you can modify on your phone, including
-        those of friends or co-workers. This may allow the app to send messages
-        that appear to come from calendar owners, or modify events without the
-        owners\' knowledge.</string>
+    <string name="permdesc_writeCalendar" product="default">This app can add, remove, or change calendar events on your phone. This app can send messages that may appear to come from calendar owners, or change events without notifying their owners.</string>
 
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the applicatfion to do this. -->
     <string name="permlab_accessLocationExtraCommands">access extra location provider commands</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_accessLocationExtraCommands">Allows the app to access
@@ -989,23 +953,17 @@
     <string name="permlab_accessFineLocation">access precise location (GPS and
       network-based)</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accessFineLocation">Allows the app to get your
-      precise location using the Global Positioning System (GPS) or network
-      location sources such as cell towers and Wi-Fi. These location services
-      must be turned on and available to your device for the app to use them.
-      Apps may use this to determine where you are, and may consume additional
-      battery power.</string>
+    <string name="permdesc_accessFineLocation">This app can get your location based on GPS or network location sources such as cell towers and Wi-Fi networks. These location services must be turned on and available on your phone for the app to be able to use them. This may increase battery consumption.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_accessCoarseLocation">access approximate location
       (network-based)</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accessCoarseLocation">Allows the app to get your
-      approximate location. This location is derived by location services using
-      network location sources such as cell towers and Wi-Fi. These location
-      services must be turned on and available to your device for the app to
-      use them. Apps may use this to determine approximately where you
-      are.</string>
+    <string name="permdesc_accessCoarseLocation" product="tablet">This app can get your location based on network sources such as cell towers and Wi-Fi networks. These location services must be turned on and available on your tablet for the app to be able to use them.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_accessCoarseLocation" product="tv">This app can get your location based on network sources such as cell towers and Wi-Fi networks. These location services must be turned on and available on your TV for the app to be able to use them.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_accessCoarseLocation" product="default">This app can get your location based on network sources such as cell towers and Wi-Fi networks. These location services must be turned on and available on your phone for the app to be able to use them.</string>
 
  <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_modifyAudioSettings">change your audio settings</string>
@@ -1015,9 +973,7 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_recordAudio">record audio</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_recordAudio">Allows the app to record audio with the
-      microphone.  This permission allows the app to record audio at any time
-      without your confirmation.</string>
+    <string name="permdesc_recordAudio">This app can record audio using the microphone at any time.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_sim_communication">send commands to the SIM</string>
@@ -1027,9 +983,7 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_camera">take pictures and videos</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_camera">Allows the app to take pictures and videos
-      with the camera.  This permission allows the app to use the camera at any
-      time without your confirmation.</string>
+    <string name="permdesc_camera">This app can take pictures and record videos using the camera at any time.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_vibrate">control vibration</string>
@@ -2431,22 +2385,6 @@
     <!-- Appened to express the value is this unit of time. -->
     <string name="years">years</string>
 
-    <!-- Phrase describing a time duration using seconds [CHAR LIMIT=16] -->
-    <plurals name="duration_seconds">
-        <item quantity="one">1 second</item>
-        <item quantity="other"><xliff:g id="count">%d</xliff:g> seconds</item>
-    </plurals>
-    <!-- Phrase describing a time duration using minutes [CHAR LIMIT=16] -->
-    <plurals name="duration_minutes">
-        <item quantity="one">1 minute</item>
-        <item quantity="other"><xliff:g id="count">%d</xliff:g> minutes</item>
-    </plurals>
-    <!-- Phrase describing a time duration using hours [CHAR LIMIT=16] -->
-    <plurals name="duration_hours">
-        <item quantity="one">1 hour</item>
-        <item quantity="other"><xliff:g id="count">%d</xliff:g> hours</item>
-    </plurals>
-
     <!-- A string denoting the current point in time that should be as short as possible. Abbreviations are preferred to full strings as this might be shown repetitively. It is used in the header of notifications. [CHAR LIMIT=8]-->
     <string name="now_string_shortest">now</string>
 
@@ -4277,7 +4215,7 @@
     <string name="zen_mode_alarm">Until <xliff:g id="formattedTime" example="10:00 PM">%1$s</xliff:g> (next alarm)</string>
 
     <!-- Zen mode condition: no exit criteria. [CHAR LIMIT=NONE] -->
-    <string name="zen_mode_forever">Until you turn this off</string>
+    <string name="zen_mode_forever">Until you turn off Do Not Disturb</string>
 
     <!-- Zen mode condition: no exit criteria, includes the name of the feature for emphasis. [CHAR LIMIT=NONE] -->
     <string name="zen_mode_forever_dnd">Until you turn off Do Not Disturb</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a85ddf1..7c50f62 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -307,6 +307,7 @@
   <java-symbol type="bool" name="config_supportAudioSourceUnprocessed" />
   <java-symbol type="bool" name="config_freeformWindowManagement" />
   <java-symbol type="bool" name="config_supportsMultiWindow" />
+  <java-symbol type="bool" name="config_supportsSplitScreenMultiWindow" />
   <java-symbol type="bool" name="config_guestUserEphemeral" />
   <java-symbol type="bool" name="config_localDisplaysMirrorContent" />
   <java-symbol type="integer" name="config_defaultDisplayDefaultColorMode" />
@@ -493,6 +494,8 @@
   <java-symbol type="string" name="RestrictedOnData" />
   <java-symbol type="string" name="RestrictedOnEmergency" />
   <java-symbol type="string" name="RestrictedOnNormal" />
+  <java-symbol type="string" name="NetworkPreferenceSwitchSummary" />
+  <java-symbol type="string" name="NetworkPreferenceSwitchTitle" />
   <java-symbol type="string" name="SetupCallDefault" />
   <java-symbol type="string" name="accept" />
   <java-symbol type="string" name="accessibility_enabled" />
@@ -732,6 +735,7 @@
   <java-symbol type="string" name="mmiComplete" />
   <java-symbol type="string" name="mmiError" />
   <java-symbol type="string" name="mmiFdnError" />
+  <java-symbol type="string" name="mmiErrorWhileRoaming" />
   <java-symbol type="string" name="month_day_year" />
   <java-symbol type="string" name="more_item_label" />
   <java-symbol type="string" name="needPuk" />
@@ -1124,6 +1128,7 @@
   <java-symbol type="string" name="config_ethernet_tcp_buffers" />
   <java-symbol type="string" name="config_wifi_tcp_buffers" />
   <java-symbol type="string" name="config_demoModeLauncherComponent" />
+  <java-symbol type="string" name="config_demoModePassword" />
   <java-symbol type="string" name="demo_starting_message" />
   <java-symbol type="string" name="demo_restarting_message" />
   <java-symbol type="string" name="conference_call" />
@@ -1131,9 +1136,6 @@
 
 
   <java-symbol type="plurals" name="bugreport_countdown" />
-  <java-symbol type="plurals" name="duration_hours" />
-  <java-symbol type="plurals" name="duration_minutes" />
-  <java-symbol type="plurals" name="duration_seconds" />
   <java-symbol type="plurals" name="last_num_days" />
   <java-symbol type="plurals" name="matches_found" />
   <java-symbol type="plurals" name="restr_pin_countdown" />
@@ -2753,6 +2755,9 @@
 
   <java-symbol type="dimen" name="config_appTransitionAnimationDurationScaleDefault" />
 
-<!-- Network Recommendation -->
+  <!-- Network Recommendation -->
   <java-symbol type="array" name="config_networkRecommendationPackageNames" />
+
+  <!-- Whether allow 3rd party apps on internal storage. -->
+  <java-symbol type="bool" name="config_allow3rdPartyAppOnInternal" />
 </resources>
diff --git a/core/tests/coretests/src/android/content/pm/PackageHelperTests.java b/core/tests/coretests/src/android/content/pm/PackageHelperTests.java
index 5af2667..c4d00c6 100644
--- a/core/tests/coretests/src/android/content/pm/PackageHelperTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageHelperTests.java
@@ -16,17 +16,28 @@
 
 package android.content.pm;
 
-import static android.net.TrafficStats.MB_IN_BYTES;
-
+import android.content.Context;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.storage.IStorageManager;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
 import com.android.internal.content.PackageHelper;
 
+import org.mockito.Mockito;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static android.net.TrafficStats.MB_IN_BYTES;
+import static android.os.storage.VolumeInfo.STATE_MOUNTED;
+
 public class PackageHelperTests extends AndroidTestCase {
     private static final boolean localLOGV = true;
     public static final String TAG = "PackageHelperTests";
@@ -35,6 +46,94 @@
     private String fullId;
     private String fullId2;
 
+    private static final String sInternalVolPath = "/data";
+    private static final String sAdoptedVolPath = "/mnt/expand/123";
+    private static final String sPublicVolPath = "/emulated";
+
+    private static final String sInternalVolUuid = StorageManager.UUID_PRIVATE_INTERNAL;
+    private static final String sAdoptedVolUuid = "adopted";
+    private static final String sPublicVolUuid = "emulated";
+
+    private static final long sInternalSize = 20000;
+    private static final long sAdoptedSize = 10000;
+    private static final long sPublicSize = 1000000;
+
+    private static final StorageManager sStorageManager = createStorageManagerMock();
+
+    private static StorageManager createStorageManagerMock() {
+        VolumeInfo internalVol = new VolumeInfo("private",
+                VolumeInfo.TYPE_PRIVATE, null /*DiskInfo*/, null /*partGuid*/);
+        internalVol.path = sInternalVolPath;
+        internalVol.state = STATE_MOUNTED;
+        internalVol.fsUuid = sInternalVolUuid;
+
+        VolumeInfo adoptedVol = new VolumeInfo("adopted",
+                VolumeInfo.TYPE_PRIVATE, null /*DiskInfo*/, null /*partGuid*/);
+        adoptedVol.path = sAdoptedVolPath;
+        adoptedVol.state = STATE_MOUNTED;
+        adoptedVol.fsUuid = sAdoptedVolUuid;
+
+        VolumeInfo publicVol = new VolumeInfo("public",
+                VolumeInfo.TYPE_PUBLIC, null /*DiskInfo*/, null /*partGuid*/);
+        publicVol.state = STATE_MOUNTED;
+        publicVol.path = sPublicVolPath;
+        publicVol.fsUuid = sPublicVolUuid;
+
+        List<VolumeInfo> volumes = new ArrayList<>();
+        volumes.add(internalVol);
+        volumes.add(adoptedVol);
+        volumes.add(publicVol);
+
+        StorageManager storageManager = Mockito.mock(StorageManager.class);
+        Mockito.when(storageManager.getVolumes()).thenReturn(volumes);
+
+        File internalFile = new File(sInternalVolPath);
+        File adoptedFile = new File(sAdoptedVolPath);
+        File publicFile = new File(sPublicVolPath);
+        Mockito.when(storageManager.getStorageBytesUntilLow(internalFile)).thenReturn(sInternalSize);
+        Mockito.when(storageManager.getStorageBytesUntilLow(adoptedFile)).thenReturn(sAdoptedSize);
+        Mockito.when(storageManager.getStorageBytesUntilLow(publicFile)).thenReturn(sPublicSize);
+        return storageManager;
+    }
+
+    private static final class MockedInterface extends PackageHelper.TestableInterface {
+        private boolean mForceAllowOnExternal = false;
+        private boolean mAllow3rdPartyOnInternal = true;
+        private ApplicationInfo mApplicationInfo = null;
+
+        public void setMockValues(ApplicationInfo applicationInfo,
+                boolean forceAllowOnExternal, boolean allow3rdPartyOnInternal) {
+            mForceAllowOnExternal = forceAllowOnExternal;
+            mAllow3rdPartyOnInternal = allow3rdPartyOnInternal;
+            mApplicationInfo = applicationInfo;
+        }
+
+        @Override
+        public StorageManager getStorageManager(Context context) {
+            return sStorageManager;
+        }
+
+        @Override
+        public boolean getForceAllowOnExternalSetting(Context context) {
+            return mForceAllowOnExternal;
+        }
+
+        @Override
+        public boolean getAllow3rdPartyOnInternalConfig(Context context) {
+            return mAllow3rdPartyOnInternal;
+        }
+
+        @Override
+        public ApplicationInfo getExistingAppInfo(Context context, String packagename) {
+            return mApplicationInfo;
+        }
+
+        @Override
+        public File getDataDirectory() {
+            return new File(sInternalVolPath);
+        }
+    }
+
     private IStorageManager getSm() {
         IBinder service = ServiceManager.getService("mount");
         if (service != null) {
@@ -131,4 +230,328 @@
         };
         return r;
     }
+
+    public void testResolveInstallVolumeInternal_SystemApp() throws IOException {
+        ApplicationInfo systemAppInfo = new ApplicationInfo();
+        systemAppInfo.flags = ApplicationInfo.FLAG_SYSTEM;
+
+        // All test cases for when the system app fits on internal.
+        MockedInterface mockedInterface = new MockedInterface();
+        mockedInterface.setMockValues(systemAppInfo, false /*force allow on external*/,
+                true /*allow 3rd party on internal*/);
+        String volume = null;
+        volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+            1 /*install location*/, 1000 /*size bytes*/, mockedInterface);
+        assertEquals(StorageManager.UUID_PRIVATE_INTERNAL, volume);
+
+        mockedInterface.setMockValues(systemAppInfo, true /*force allow on external*/,
+                true /*allow 3rd party on internal*/);
+        volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                1 /*install location*/, 1000 /*size bytes*/, mockedInterface);
+        assertEquals(StorageManager.UUID_PRIVATE_INTERNAL, volume);
+
+        mockedInterface.setMockValues(systemAppInfo, false /*force allow on external*/,
+                false /*allow 3rd party on internal*/);
+        volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                1 /*install location*/, 1000 /*size bytes*/, mockedInterface);
+        assertEquals(StorageManager.UUID_PRIVATE_INTERNAL, volume);
+
+        mockedInterface.setMockValues(systemAppInfo, true /*force allow on external*/,
+                false /*allow 3rd party on internal*/);
+        volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                1 /*install location*/, 1000 /*size bytes*/, mockedInterface);
+        assertEquals(StorageManager.UUID_PRIVATE_INTERNAL, volume);
+
+
+        // All test cases for when the system app does not fit on internal.
+        // Exception should be thrown.
+        mockedInterface.setMockValues(systemAppInfo, true /*force allow on external*/,
+                true /*allow 3rd party on internal*/);
+        try {
+            PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                    1 /*install location*/, 1000000 /*size bytes*/, mockedInterface);
+            fail("Expected exception in resolveInstallVolume was not thrown");
+        } catch(IOException e) {
+            // expected
+        }
+
+        mockedInterface.setMockValues(systemAppInfo, false /*force allow on external*/,
+                true /*allow 3rd party on internal*/);
+        try {
+            PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                    1 /*install location*/, 1000000 /*size bytes*/, mockedInterface);
+            fail("Expected exception in resolveInstallVolume was not thrown");
+        } catch(IOException e) {
+            // expected
+        }
+
+        mockedInterface.setMockValues(systemAppInfo, false /*force allow on external*/,
+                false /*allow 3rd party on internal*/);
+        try {
+            PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                    1 /*install location*/, 1000000 /*size bytes*/, mockedInterface);
+            fail("Expected exception in resolveInstallVolume was not thrown");
+        } catch(IOException e) {
+            // expected
+        }
+
+        mockedInterface.setMockValues(systemAppInfo, true /*force allow on external*/,
+                false /*allow 3rd party on internal*/);
+        try {
+            PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                    1 /*install location*/, 1000000 /*size bytes*/, mockedInterface);
+            fail("Expected exception in resolveInstallVolume was not thrown");
+        } catch(IOException e) {
+            // expected
+        }
+    }
+
+    public void testResolveInstallVolumeInternal_3rdParty_existing_not_too_big()
+            throws IOException {
+        // Existing apps always stay on the same volume.
+        // Test cases for existing app on internal.
+        ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.volumeUuid = sInternalVolUuid;
+        MockedInterface mockedInterface = new MockedInterface();
+        mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
+                true /*allow 3rd party on internal*/);
+        String volume = null;
+        volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                0 /*install location*/, 1000 /*size bytes*/, mockedInterface);
+        assertEquals(sInternalVolUuid, volume);
+
+        mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
+                true /*allow 3rd party on internal*/);
+        volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                0 /*install location*/, 1000 /*size bytes*/, mockedInterface);
+        assertEquals(sInternalVolUuid, volume);
+    }
+
+    public void testResolveInstallVolumeInternal_3rdParty_existing_not_too_big_adopted()
+            throws IOException {
+        // Test cases for existing app on the adopted media.
+        ApplicationInfo appInfo = new ApplicationInfo();
+        MockedInterface mockedInterface = new MockedInterface();
+        String volume;
+        appInfo.volumeUuid = sAdoptedVolUuid;
+        mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
+                true /*allow 3rd party on internal*/);
+        volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+            0 /*install location*/, 1000 /*size bytes*/, mockedInterface);
+        assertEquals(sAdoptedVolUuid, volume);
+
+        mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
+                true /*allow 3rd party on internal*/);
+        volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                0 /*install location*/, 1000 /*size bytes*/, mockedInterface);
+        assertEquals(sAdoptedVolUuid, volume);
+
+        mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
+                false /*allow 3rd party on internal*/);
+        volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                0 /*install location*/, 1000 /*size bytes*/, mockedInterface);
+        assertEquals(sAdoptedVolUuid, volume);
+
+        mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
+                false /*allow 3rd party on internal*/);
+        volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                0 /*install location*/, 1000 /*size bytes*/, mockedInterface);
+        assertEquals(sAdoptedVolUuid, volume);
+    }
+
+    public void testResolveInstallVolumeAdopted_3rdParty_existing_too_big() {
+        // Test: update size too big, will throw exception.
+        ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.volumeUuid = sAdoptedVolUuid;
+
+        MockedInterface mockedInterface = new MockedInterface();
+        mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
+                true /*allow 3rd party on internal*/);
+        try {
+            PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                    0 /*install location*/, 10000001 /*BIG size, won't fit*/, mockedInterface);
+            fail("Expected exception was not thrown " + appInfo.volumeUuid);
+        } catch (IOException e) {
+            //expected
+        }
+
+        mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
+                false /*allow 3rd party on internal*/);
+        try {
+            PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                    0 /*install location*/, 10000001 /*BIG size, won't fit*/, mockedInterface);
+            fail("Expected exception was not thrown " + appInfo.volumeUuid);
+        } catch (IOException e) {
+            //expected
+        }
+
+        mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
+                false /*allow 3rd party on internal*/);
+        try {
+            PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                    0 /*install location*/, 10000001 /*BIG size, won't fit*/, mockedInterface);
+            fail("Expected exception was not thrown " + appInfo.volumeUuid);
+        } catch (IOException e) {
+            //expected
+        }
+
+        mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
+                true /*allow 3rd party on internal*/);
+        try {
+            PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                    0 /*install location*/, 10000001 /*BIG size, won't fit*/, mockedInterface);
+            fail("Expected exception was not thrown " + appInfo.volumeUuid);
+        } catch (IOException e) {
+            //expected
+        }
+    }
+
+    public void testResolveInstallVolumeInternal_3rdParty_auto() throws IOException {
+        ApplicationInfo appInfo = null;
+        MockedInterface mockedInterface = new MockedInterface();
+        mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
+                true /*allow 3rd party on internal*/);
+        String volume = null;
+        volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+            0 /*install location auto*/, 1000 /*size bytes*/, mockedInterface);
+        // Should return the volume with bigger available space.
+        assertEquals(sInternalVolUuid, volume);
+
+        mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
+                true /*allow 3rd party on internal*/);
+        volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                0 /*install location auto*/, 1000 /*size bytes*/, mockedInterface);
+        // Should return the volume with bigger available space.
+        assertEquals(sInternalVolUuid, volume);
+
+        mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
+                false /*allow 3rd party on internal*/);
+        volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                0 /*install location auto*/, 1000 /*size bytes*/, mockedInterface);
+        // Should return the volume with bigger available space.
+        assertEquals(sAdoptedVolUuid, volume);
+
+        mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
+                false /*allow 3rd party on internal*/);
+        volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                0 /*install location auto*/, 1000 /*size bytes*/, mockedInterface);
+        // Should return the volume with bigger available space.
+        assertEquals(sAdoptedVolUuid, volume);
+
+
+    }
+
+    public void testResolveInstallVolumeInternal_3rdParty_internal_only() throws IOException {
+        ApplicationInfo appInfo = null;
+        MockedInterface mockedInterface = new MockedInterface();
+        mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
+                true /*allow 3rd party on internal*/);
+        String volume = null;
+        volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+            1 /*install location internal ONLY*/, 1000 /*size bytes*/, mockedInterface);
+        assertEquals(sInternalVolUuid, volume);
+
+        mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
+                true /*allow 3rd party on internal*/);
+        volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                1 /*install location internal ONLY*/, 1000 /*size bytes*/, mockedInterface);
+        assertEquals(sInternalVolUuid, volume);
+
+        mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
+                false /*allow 3rd party on internal*/);
+        try {
+            volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                    1 /*install location internal only*/, 1000 /*size bytes*/, mockedInterface);
+            fail("Expected exception in resolveInstallVolume was not thrown");
+        } catch (IOException e) {
+            //expected
+        }
+
+        appInfo = null;
+        mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
+                false /*allow 3rd party on internal*/);
+        volume = null;
+        volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                1 /*install location internal only*/, 1000 /*size bytes*/, mockedInterface);
+        assertEquals(sAdoptedVolUuid, volume);
+    }
+
+    public void testResolveInstallVolumeInternal_3rdParty_not_allowed_on_internal()
+        throws IOException {
+        ApplicationInfo appInfo = null;
+        MockedInterface mockedInterface = new MockedInterface();
+        mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
+                false /*allow 3rd party on internal*/);
+        String volume = null;
+        volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+            0 /*install location auto*/, 1000 /*size bytes*/, mockedInterface);
+        // Should return the non-internal volume.
+        assertEquals(sAdoptedVolUuid, volume);
+
+        appInfo = null;
+        mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
+                false /*allow 3rd party on internal*/);
+        volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                0 /*install location auto*/, 1000 /*size bytes*/, mockedInterface);
+        // Should return the non-internal volume.
+        assertEquals(sAdoptedVolUuid, volume);
+    }
+
+    public void testResolveInstallVolumeInternal_3rdParty_internal_only_too_big() {
+        ApplicationInfo appInfo = null;
+        MockedInterface mockedInterface = new MockedInterface();
+        mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
+                true /*allow 3rd party on internal*/);
+        String volume = null;
+        try {
+            volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                    1 /*install location internal ONLY*/,
+                    1000000 /*size too big*/, mockedInterface);
+            fail("Expected exception in resolveInstallVolume was not thrown");
+        } catch (IOException e) {
+            //expected
+        }
+    }
+
+    public void testResolveInstallVolumeInternal_3rdParty_internal_only_not_allowed()
+        throws IOException {
+        ApplicationInfo appInfo = null;
+        MockedInterface mockedInterface = new MockedInterface();
+        mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
+                false /*allow 3rd party on internal*/);
+        String volume = null;
+        try {
+            volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+                    1 /*install location internal only*/, 1000 /*size bytes*/, mockedInterface);
+            fail("Expected exception in resolveInstallVolume was not thrown");
+        } catch (IOException e) {
+            //expected
+        }
+
+        appInfo = null;
+        mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
+                false /*allow 3rd party on internal*/);
+        volume = null;
+        volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+            1 /*install location internal only*/, 1000 /*size bytes*/, mockedInterface);
+        assertEquals(sAdoptedVolUuid, volume);
+
+    }
+
+    public void testResolveInstallVolumeInternal_3rdParty_internal_only_forced_to_external()
+        throws IOException {
+        // New/existing installation: New
+        // app request location: Internal Only
+        // 3rd party allowed on internal: False
+        // Force allow external in setting: True
+        // Size fit? Yes
+        ApplicationInfo appInfo = null;
+        MockedInterface mockedInterface = new MockedInterface();
+        mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
+                false /*allow 3rd party on internal*/);
+        String volume = null;
+        volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
+            1 /*install location internal only*/, 1000 /*size bytes*/, mockedInterface);
+        assertEquals(sAdoptedVolUuid, volume);
+    }
 }
diff --git a/core/tests/coretests/src/android/content/res/ConfigurationTest.java b/core/tests/coretests/src/android/content/res/ConfigurationTest.java
new file mode 100644
index 0000000..72b9197
--- /dev/null
+++ b/core/tests/coretests/src/android/content/res/ConfigurationTest.java
@@ -0,0 +1,58 @@
+/*
+1;3409;0c * 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.content.res;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+import org.junit.runners.JUnit4;
+
+import android.content.res.Configuration;
+import android.support.test.filters.SmallTest;
+import android.platform.test.annotations.Presubmit;
+
+import junit.framework.TestCase;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Build/install/run: bit FrameworksCoreTests:android.content.res.ConfigurationTest
+ */
+@RunWith(JUnit4.class)
+@SmallTest
+@Presubmit
+public class ConfigurationTest extends TestCase {
+    @Test
+    public void testUpdateFromPreservesRoundBit() {
+        Configuration config = new Configuration();
+        config.screenLayout = Configuration.SCREENLAYOUT_ROUND_YES;
+        Configuration config2 = new Configuration();
+
+        config.updateFrom(config2);
+        assertEquals(config.screenLayout, Configuration.SCREENLAYOUT_ROUND_YES);
+    }
+
+    @Test
+    public void testUpdateFromPreservesCompatNeededBit() {
+        Configuration config = new Configuration();
+        config.screenLayout = Configuration.SCREENLAYOUT_COMPAT_NEEDED;
+        Configuration config2 = new Configuration();
+        config.updateFrom(config2);
+        assertEquals(config.screenLayout, Configuration.SCREENLAYOUT_COMPAT_NEEDED);
+
+        config2.updateFrom(config);
+        assertEquals(config2.screenLayout, Configuration.SCREENLAYOUT_COMPAT_NEEDED);
+    }
+}
diff --git a/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java b/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java
new file mode 100644
index 0000000..9a81401
--- /dev/null
+++ b/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java
@@ -0,0 +1,161 @@
+package android.net;
+
+import static android.net.NetworkRecommendationProvider.EXTRA_RECOMMENDATION_RESULT;
+import static android.net.NetworkRecommendationProvider.EXTRA_SEQUENCE;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IRemoteCallback;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Unit test for the {@link NetworkRecommendationProvider}.
+ */
+public class NetworkRecommendationProviderTest extends InstrumentationTestCase {
+    @Mock private IRemoteCallback mMockRemoteCallback;
+    private NetworkRecProvider mRecProvider;
+    private Handler mHandler;
+    private INetworkRecommendationProvider mStub;
+    private CountDownLatch mRecRequestLatch;
+    private CountDownLatch mScoreRequestLatch;
+    private NetworkKey[] mTestNetworkKeys;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        // Configuration needed to make mockito/dexcache work.
+        final Context context = getInstrumentation().getTargetContext();
+        System.setProperty("dexmaker.dexcache",
+                context.getCacheDir().getPath());
+        ClassLoader newClassLoader = getInstrumentation().getClass().getClassLoader();
+        Thread.currentThread().setContextClassLoader(newClassLoader);
+
+        MockitoAnnotations.initMocks(this);
+
+        HandlerThread thread = new HandlerThread("NetworkRecommendationProviderTest");
+        thread.start();
+        mRecRequestLatch = new CountDownLatch(1);
+        mScoreRequestLatch = new CountDownLatch(1);
+        mHandler = new Handler(thread.getLooper());
+        mRecProvider = new NetworkRecProvider(mHandler, mRecRequestLatch, mScoreRequestLatch);
+        mStub = INetworkRecommendationProvider.Stub.asInterface(mRecProvider.getBinder());
+        mTestNetworkKeys = new NetworkKey[2];
+        mTestNetworkKeys[0] = new NetworkKey(new WifiKey("\"ssid_01\"", "00:00:00:00:00:11"));
+        mTestNetworkKeys[1] = new NetworkKey(new WifiKey("\"ssid_02\"", "00:00:00:00:00:22"));
+    }
+
+    @MediumTest
+    public void testRecommendationRequestReceived() throws Exception {
+        final RecommendationRequest request = new RecommendationRequest.Builder().build();
+        final int sequence = 100;
+        mStub.requestRecommendation(request, mMockRemoteCallback, sequence);
+
+        // wait for onRequestRecommendation() to be called in our impl below.
+        mRecRequestLatch.await(200, TimeUnit.MILLISECONDS);
+        NetworkRecommendationProvider.ResultCallback expectedResultCallback =
+                new NetworkRecommendationProvider.ResultCallback(mMockRemoteCallback, sequence);
+        assertEquals(request, mRecProvider.mCapturedRequest);
+        assertEquals(expectedResultCallback, mRecProvider.mCapturedCallback);
+    }
+
+    @SmallTest
+    public void testResultCallbackOnResult() throws Exception {
+        final int sequence = 100;
+        final NetworkRecommendationProvider.ResultCallback callback =
+                new NetworkRecommendationProvider.ResultCallback(mMockRemoteCallback, sequence);
+
+        final RecommendationResult result = new RecommendationResult(null);
+        callback.onResult(result);
+
+        final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
+        Mockito.verify(mMockRemoteCallback).sendResult(bundleCaptor.capture());
+        Bundle capturedBundle = bundleCaptor.getValue();
+        assertEquals(sequence, capturedBundle.getInt(EXTRA_SEQUENCE));
+        assertSame(result, capturedBundle.getParcelable(EXTRA_RECOMMENDATION_RESULT));
+    }
+
+    @SmallTest
+    public void testResultCallbackOnResult_runTwice_throwsException() throws Exception {
+        final int sequence = 100;
+        final NetworkRecommendationProvider.ResultCallback callback =
+                new NetworkRecommendationProvider.ResultCallback(mMockRemoteCallback, sequence);
+
+        final RecommendationResult result = new RecommendationResult(null);
+        callback.onResult(result);
+
+        try {
+            callback.onResult(result);
+            fail("Callback ran more than once.");
+        } catch (IllegalStateException e) {
+            // expected
+        }
+    }
+
+    @MediumTest
+    public void testScoreRequestReceived() throws Exception {
+        mStub.requestScores(mTestNetworkKeys);
+
+        // wait for onRequestScores() to be called in our impl below.
+        mScoreRequestLatch.await(200, TimeUnit.MILLISECONDS);
+
+        assertSame(mTestNetworkKeys, mRecProvider.mCapturedNetworks);
+    }
+
+    @MediumTest
+    public void testScoreRequest_nullInput() throws Exception {
+        mStub.requestScores(null);
+
+        // onRequestScores() should never be called
+        assertFalse(mScoreRequestLatch.await(200, TimeUnit.MILLISECONDS));
+    }
+
+    @MediumTest
+    public void testScoreRequest_emptyInput() throws Exception {
+        mStub.requestScores(new NetworkKey[0]);
+
+        // onRequestScores() should never be called
+        assertFalse(mScoreRequestLatch.await(200, TimeUnit.MILLISECONDS));
+    }
+
+    private static class NetworkRecProvider extends NetworkRecommendationProvider {
+        private final CountDownLatch mRecRequestLatch;
+        private final CountDownLatch mScoreRequestLatch;
+        RecommendationRequest mCapturedRequest;
+        ResultCallback mCapturedCallback;
+        NetworkKey[] mCapturedNetworks;
+
+        NetworkRecProvider(Handler handler, CountDownLatch recRequestLatch,
+            CountDownLatch networkRequestLatch) {
+            super(handler);
+            mRecRequestLatch = recRequestLatch;
+            mScoreRequestLatch = networkRequestLatch;
+        }
+
+        @Override
+        public void onRequestRecommendation(RecommendationRequest request,
+                ResultCallback callback) {
+            mCapturedRequest = request;
+            mCapturedCallback = callback;
+            mRecRequestLatch.countDown();
+        }
+
+        @Override
+        public void onRequestScores(NetworkKey[] networks) {
+            mCapturedNetworks = networks;
+            mScoreRequestLatch.countDown();
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/text/format/DateUtilsTest.java b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
index 909f971..de43fc6 100644
--- a/core/tests/coretests/src/android/text/format/DateUtilsTest.java
+++ b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
@@ -61,6 +61,18 @@
         assertEquals("1 second", DateUtils.formatDuration(500));
         assertEquals("1 second", DateUtils.formatDuration(1000));
         assertEquals("2 seconds", DateUtils.formatDuration(1500));
+
+        assertEquals("0 seconds", DateUtils.formatDuration(0, DateUtils.LENGTH_LONG));
+        assertEquals("1 second", DateUtils.formatDuration(1000, DateUtils.LENGTH_LONG));
+        assertEquals("2 seconds", DateUtils.formatDuration(1500, DateUtils.LENGTH_LONG));
+
+        assertEquals("0 sec", DateUtils.formatDuration(0, DateUtils.LENGTH_SHORT));
+        assertEquals("1 sec", DateUtils.formatDuration(1000, DateUtils.LENGTH_SHORT));
+        assertEquals("2 sec", DateUtils.formatDuration(1500, DateUtils.LENGTH_SHORT));
+
+        assertEquals("0s", DateUtils.formatDuration(0, DateUtils.LENGTH_SHORTEST));
+        assertEquals("1s", DateUtils.formatDuration(1000, DateUtils.LENGTH_SHORTEST));
+        assertEquals("2s", DateUtils.formatDuration(1500, DateUtils.LENGTH_SHORTEST));
     }
 
     @SmallTest
@@ -69,6 +81,15 @@
         assertEquals("60 seconds", DateUtils.formatDuration(59500));
         assertEquals("1 minute", DateUtils.formatDuration(60000));
         assertEquals("2 minutes", DateUtils.formatDuration(120000));
+
+        assertEquals("1 minute", DateUtils.formatDuration(60000, DateUtils.LENGTH_LONG));
+        assertEquals("2 minutes", DateUtils.formatDuration(120000, DateUtils.LENGTH_LONG));
+
+        assertEquals("1 min", DateUtils.formatDuration(60000, DateUtils.LENGTH_SHORT));
+        assertEquals("2 min", DateUtils.formatDuration(120000, DateUtils.LENGTH_SHORT));
+
+        assertEquals("1m", DateUtils.formatDuration(60000, DateUtils.LENGTH_SHORTEST));
+        assertEquals("2m", DateUtils.formatDuration(120000, DateUtils.LENGTH_SHORTEST));
     }
 
     @SmallTest
@@ -76,5 +97,14 @@
         assertEquals("59 minutes", DateUtils.formatDuration(3540000));
         assertEquals("1 hour", DateUtils.formatDuration(3600000));
         assertEquals("48 hours", DateUtils.formatDuration(172800000));
+
+        assertEquals("1 hour", DateUtils.formatDuration(3600000, DateUtils.LENGTH_LONG));
+        assertEquals("48 hours", DateUtils.formatDuration(172800000, DateUtils.LENGTH_LONG));
+
+        assertEquals("1 hr", DateUtils.formatDuration(3600000, DateUtils.LENGTH_SHORT));
+        assertEquals("48 hr", DateUtils.formatDuration(172800000, DateUtils.LENGTH_SHORT));
+
+        assertEquals("1h", DateUtils.formatDuration(3600000, DateUtils.LENGTH_SHORTEST));
+        assertEquals("48h", DateUtils.formatDuration(172800000, DateUtils.LENGTH_SHORTEST));
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
index a15e367..f1aeecc 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
@@ -18,12 +18,9 @@
 import android.os.BatteryStats;
 import android.os.Parcel;
 import android.support.test.filters.SmallTest;
-import android.util.Log;
 
 import junit.framework.TestCase;
 
-import org.mockito.Mockito;
-
 /**
  * Test BatteryStatsImpl.DurationTimer.
  *
@@ -39,7 +36,7 @@
         final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase();
         timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime());
 
-        final BatteryStatsImpl.DurationTimer timer = new BatteryStatsImpl.DurationTimer(clocks, 
+        final BatteryStatsImpl.DurationTimer timer = new BatteryStatsImpl.DurationTimer(clocks,
                 null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase);
 
         // TimeBase running, timer not running: current and max are 0
@@ -82,15 +79,15 @@
         // Stop the TimeBase. The values should be frozen.
         timeBase.setRunning(false, /* uptimeUs */ 10, /* realtimeUs */ 55000*1000);
         assertTrue(timer.isRunningLocked());
-        assertEquals(28100, timer.getCurrentDurationMsLocked(110100)); // Why 28100 and not 28000?
-        assertEquals(28100, timer.getMaxDurationMsLocked(110101));
+        assertEquals(28000, timer.getCurrentDurationMsLocked(110100));
+        assertEquals(28000, timer.getMaxDurationMsLocked(110101));
 
         // Start the TimeBase. The values should be the old value plus the delta
         // between when the timer restarted and the current time
         timeBase.setRunning(true, /* uptimeUs */ 10, /* realtimeUs */ 220100*1000);
         assertTrue(timer.isRunningLocked());
-        assertEquals(28300, timer.getCurrentDurationMsLocked(220300)); // extra 100 from above??
-        assertEquals(28301, timer.getMaxDurationMsLocked(220301));
+        assertEquals(28200, timer.getCurrentDurationMsLocked(220300));
+        assertEquals(28201, timer.getMaxDurationMsLocked(220301));
     }
 
     @SmallTest
@@ -104,7 +101,7 @@
         final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase();
         timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime());
 
-        final BatteryStatsImpl.DurationTimer timer = new BatteryStatsImpl.DurationTimer(clocks, 
+        final BatteryStatsImpl.DurationTimer timer = new BatteryStatsImpl.DurationTimer(clocks,
                 null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase);
 
         // Start running on battery.
@@ -124,7 +121,7 @@
         summaryParcel.setDataPosition(0);
 
         // Read summary
-        final BatteryStatsImpl.DurationTimer summary = new BatteryStatsImpl.DurationTimer(clocks, 
+        final BatteryStatsImpl.DurationTimer summary = new BatteryStatsImpl.DurationTimer(clocks,
                 null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase);
         summary.startRunningLocked(3100);
         summary.readSummaryFromParcelLocked(summaryParcel);
@@ -138,9 +135,9 @@
         final Parcel fullParcel = Parcel.obtain();
         timer.writeToParcel(fullParcel, 1500*1000);
         fullParcel.setDataPosition(0);
- 
+
         // Read full - Should be the same as the summary as far as DurationTimer is concerned.
-        final BatteryStatsImpl.DurationTimer full = new BatteryStatsImpl.DurationTimer(clocks, 
+        final BatteryStatsImpl.DurationTimer full = new BatteryStatsImpl.DurationTimer(clocks,
                 null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase, fullParcel);
         // The new one shouldn't be running, and therefore 0 for current time
         assertFalse(full.isRunningLocked());
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index f4c5b53..5baa75b 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 # We have to use BUILD_PREBUILT instead of PRODUCT_COPY_FIES,
-# because SMALLER_FONT_FOOTPRINT is only available in Android.mks.
+# because MINIMAL_FONT_FOOTPRINT is only available in Android.mks.
 
 LOCAL_PATH := $(call my-dir)
 
@@ -59,21 +59,6 @@
 extra_font_files :=
 
 ################################
-# Include the DroidSansFallback subset on SMALLER_FONT_FOOTPRINT build
-ifeq ($(SMALLER_FONT_FOOTPRINT),true)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := DroidSansFallback.ttf
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
-include $(BUILD_PREBUILT)
-droidsans_fallback_src :=
-
-endif  # SMALLER_FONT_FOOTPRINT
-
-################################
 # Build the rest of font files as prebuilt.
 
 # $(1): The source file name in LOCAL_PATH.
@@ -101,7 +86,7 @@
 checkbuild: fontchain_lint
 
 FONTCHAIN_LINTER := frameworks/base/tools/fonts/fontchain_lint.py
-ifeq ($(SMALLER_FONT_FOOTPRINT),true)
+ifeq ($(MINIMAL_FONT_FOOTPRINT),true)
 CHECK_EMOJI := false
 else
 CHECK_EMOJI := true
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index acd785e..23c54ae 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -18,6 +18,5 @@
     frameworks/base/data/fonts/fonts.xml:$(TARGET_COPY_OUT_SYSTEM)/etc/fonts.xml
 
 PRODUCT_PACKAGES := \
-    DroidSansFallback.ttf \
     DroidSansMono.ttf \
-    AndroidClock.ttf \
+    AndroidClock.ttf
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 345ec37..465e207 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -353,9 +353,6 @@
     <family lang="und-Zsym">
         <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted2.ttf</font>
     </family>
-    <family>
-        <font weight="400" style="normal">DroidSansFallback.ttf</font>
-    </family>
     <!--
         Tai Le and Mongolian are intentionally kept last, to make sure they don't override
         the East Asian punctuation for Chinese.
diff --git a/docs/html/reference/images/graphics/colorspace_ucs.png b/docs/html/reference/images/graphics/colorspace_ucs.png
new file mode 100644
index 0000000..3e0f0c6
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_ucs.png
Binary files differ
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 756087c..a041a28 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -140,7 +140,7 @@
      * Native bitmap has been reconfigured, so set premult and cached
      * width/height values
      */
-    // called from JNI
+    @SuppressWarnings("unused") // called from JNI
     void reinit(int width, int height, boolean requestPremultiplied) {
         mWidth = width;
         mHeight = height;
@@ -465,16 +465,29 @@
          */
         ARGB_8888   (5),
 
+        /**
+         * Each pixels is stored on 8 bytes. Each channel (RGB and alpha
+         * for translucency) is stored as a
+         * {@link android.util.Half half-precision floating point value}.
+         *
+         * This configuration is particularly suited for wide-gamut and
+         * HDR content.
+         */
+        RGBA_F16    (6),
 
         /**
-          * @hide
+         * Special configuration, when bitmap is stored only in graphic memory.
+         * Bitmaps in this configuration are always immutable.
+         *
+         * It is optimal for cases, when the only operation with the bitmap is to draw it on a
+         * screen.
          */
-        HARDWARE    (6);
+        HARDWARE    (7);
 
         final int nativeInt;
 
         private static Config sConfigs[] = {
-            null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888, HARDWARE
+            null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888, RGBA_F16, HARDWARE
         };
 
         Config(int ni) {
@@ -756,6 +769,9 @@
                 case ALPHA_8:
                     newConfig = Config.ALPHA_8;
                     break;
+                case RGBA_F16:
+                    newConfig = Config.RGBA_F16;
+                    break;
                 //noinspection deprecation
                 case ARGB_4444:
                 case ARGB_8888:
@@ -777,8 +793,13 @@
             neww = Math.round(deviceR.width());
             newh = Math.round(deviceR.height());
 
-            bitmap = createBitmap(neww, newh, transformed ? Config.ARGB_8888 : newConfig,
-                    transformed || source.hasAlpha());
+            Config transformedConfig = newConfig;
+            if (transformed) {
+                if (transformedConfig != Config.ARGB_8888 && transformedConfig != Config.RGBA_F16) {
+                    transformedConfig = Config.ARGB_8888;
+                }
+            }
+            bitmap = createBitmap(neww, newh, transformedConfig, transformed || source.hasAlpha());
 
             canvas.translate(-deviceR.left, -deviceR.top);
             canvas.concat(m);
@@ -810,7 +831,8 @@
      * @param width    The width of the bitmap
      * @param height   The height of the bitmap
      * @param config   The bitmap config to create.
-     * @throws IllegalArgumentException if the width or height are <= 0
+     * @throws IllegalArgumentException if the width or height are <= 0, or if
+     *         Config is Config.HARDWARE, because hardware bitmaps are always immutable
      */
     public static Bitmap createBitmap(int width, int height, Config config) {
         return createBitmap(width, height, config, true);
@@ -825,7 +847,8 @@
      * @param width    The width of the bitmap
      * @param height   The height of the bitmap
      * @param config   The bitmap config to create.
-     * @throws IllegalArgumentException if the width or height are <= 0
+     * @throws IllegalArgumentException if the width or height are <= 0, or if
+     *         Config is Config.HARDWARE, because hardware bitmaps are always immutable
      */
     public static Bitmap createBitmap(DisplayMetrics display, int width,
             int height, Config config) {
@@ -839,13 +862,14 @@
      * @param width    The width of the bitmap
      * @param height   The height of the bitmap
      * @param config   The bitmap config to create.
-     * @param hasAlpha If the bitmap is ARGB_8888 this flag can be used to mark the
-     *                 bitmap as opaque. Doing so will clear the bitmap in black
+     * @param hasAlpha If the bitmap is ARGB_8888 or RGBA_16F this flag can be used to
+     *                 mark the bitmap as opaque. Doing so will clear the bitmap in black
      *                 instead of transparent.
      *
-     * @throws IllegalArgumentException if the width or height are <= 0
+     * @throws IllegalArgumentException if the width or height are <= 0, or if
+     *         Config is Config.HARDWARE, because hardware bitmaps are always immutable
      */
-    private static Bitmap createBitmap(int width, int height, Config config, boolean hasAlpha) {
+    public static Bitmap createBitmap(int width, int height, Config config, boolean hasAlpha) {
         return createBitmap(null, width, height, config, hasAlpha);
     }
 
@@ -858,23 +882,27 @@
      * @param width    The width of the bitmap
      * @param height   The height of the bitmap
      * @param config   The bitmap config to create.
-     * @param hasAlpha If the bitmap is ARGB_8888 this flag can be used to mark the
-     *                 bitmap as opaque. Doing so will clear the bitmap in black
+     * @param hasAlpha If the bitmap is ARGB_8888 or RGBA_16F this flag can be used to
+     *                 mark the bitmap as opaque. Doing so will clear the bitmap in black
      *                 instead of transparent.
      *
-     * @throws IllegalArgumentException if the width or height are <= 0
+     * @throws IllegalArgumentException if the width or height are <= 0, or if
+     *         Config is Config.HARDWARE, because hardware bitmaps are always immutable
      */
-    private static Bitmap createBitmap(DisplayMetrics display, int width, int height,
+    public static Bitmap createBitmap(DisplayMetrics display, int width, int height,
             Config config, boolean hasAlpha) {
         if (width <= 0 || height <= 0) {
             throw new IllegalArgumentException("width and height must be > 0");
         }
+        if (config == Config.HARDWARE) {
+            throw new IllegalArgumentException("can't create mutable bitmap with Config.HARDWARE");
+        }
         Bitmap bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true);
         if (display != null) {
             bm.mDensity = display.densityDpi;
         }
         bm.setHasAlpha(hasAlpha);
-        if (config == Config.ARGB_8888 && !hasAlpha) {
+        if ((config == Config.ARGB_8888 || config == Config.RGBA_F16) && !hasAlpha) {
             nativeErase(bm.mNativePtr, 0xff000000);
         }
         // No need to initialize the bitmap to zeroes with other configs;
@@ -1515,7 +1543,7 @@
 
     /**
      * <p>Replace pixels in the bitmap with the colors in the array. Each element
-     * in the array is a packed int prepresenting a non-premultiplied ARGB
+     * in the array is a packed int representing a non-premultiplied ARGB
      * {@link Color}.</p>
      *
      * @param pixels   The colors to write to the bitmap
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 447a4c4..a5517f0 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -16,6 +16,8 @@
 
 package android.graphics;
 
+import static android.graphics.BitmapFactory.Options.validate;
+
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.os.Trace;
@@ -103,6 +105,9 @@
          * If set, decode methods will always return a mutable Bitmap instead of
          * an immutable one. This can be used for instance to programmatically apply
          * effects to a Bitmap loaded through BitmapFactory.
+         * <p>Can not be set simultaneously with inPreferredConfig =
+         * {@link android.graphics.Bitmap.Config#HARDWARE},
+         * because hardware bitmaps are always immutable.
          */
         @SuppressWarnings({"UnusedDeclaration"}) // used in native code
         public boolean inMutable;
@@ -381,6 +386,12 @@
         public void requestCancelDecode() {
             mCancel = true;
         }
+
+        static void validate(Options opts) {
+            if (opts != null && opts.inMutable && opts.inPreferredConfig == Bitmap.Config.HARDWARE) {
+                throw new IllegalArgumentException("Bitmaps with Config.HARWARE are always immutable");
+            }
+        }
     }
 
     /**
@@ -393,8 +404,12 @@
      * @return The decoded bitmap, or null if the image data could not be
      *         decoded, or, if opts is non-null, if opts requested only the
      *         size be returned (in opts.outWidth and opts.outHeight)
+     * @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
+     *         is {@link android.graphics.Bitmap.Config#HARDWARE}
+     *         and {@link BitmapFactory.Options#inMutable} is set.
      */
     public static Bitmap decodeFile(String pathName, Options opts) {
+        validate(opts);
         Bitmap bm = null;
         InputStream stream = null;
         try {
@@ -431,10 +446,13 @@
     /**
      * Decode a new Bitmap from an InputStream. This InputStream was obtained from
      * resources, which we pass to be able to scale the bitmap accordingly.
+     * @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
+     *         is {@link android.graphics.Bitmap.Config#HARDWARE}
+     *         and {@link BitmapFactory.Options#inMutable} is set.
      */
     public static Bitmap decodeResourceStream(Resources res, TypedValue value,
             InputStream is, Rect pad, Options opts) {
-
+        validate(opts);
         if (opts == null) {
             opts = new Options();
         }
@@ -466,8 +484,12 @@
      * @return The decoded bitmap, or null if the image data could not be
      *         decoded, or, if opts is non-null, if opts requested only the
      *         size be returned (in opts.outWidth and opts.outHeight)
+     * @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
+     *         is {@link android.graphics.Bitmap.Config#HARDWARE}
+     *         and {@link BitmapFactory.Options#inMutable} is set.
      */
     public static Bitmap decodeResource(Resources res, int id, Options opts) {
+        validate(opts);
         Bitmap bm = null;
         InputStream is = null; 
         
@@ -520,11 +542,15 @@
      * @return The decoded bitmap, or null if the image data could not be
      *         decoded, or, if opts is non-null, if opts requested only the
      *         size be returned (in opts.outWidth and opts.outHeight)
+     * @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
+     *         is {@link android.graphics.Bitmap.Config#HARDWARE}
+     *         and {@link BitmapFactory.Options#inMutable} is set.
      */
     public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts) {
         if ((offset | length) < 0 || data.length < offset + length) {
             throw new ArrayIndexOutOfBoundsException();
         }
+        validate(opts);
 
         Bitmap bm;
 
@@ -598,6 +624,9 @@
      * @return The decoded bitmap, or null if the image data could not be
      *         decoded, or, if opts is non-null, if opts requested only the
      *         size be returned (in opts.outWidth and opts.outHeight)
+     * @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
+     *         is {@link android.graphics.Bitmap.Config#HARDWARE}
+     *         and {@link BitmapFactory.Options#inMutable} is set.
      *
      * <p class="note">Prior to {@link android.os.Build.VERSION_CODES#KITKAT},
      * if {@link InputStream#markSupported is.markSupported()} returns true,
@@ -610,6 +639,7 @@
         if (is == null) {
             return null;
         }
+        validate(opts);
 
         Bitmap bm = null;
 
@@ -673,8 +703,12 @@
      * @param opts null-ok; Options that control downsampling and whether the
      *             image should be completely decoded, or just its size returned.
      * @return the decoded bitmap, or null
+     * @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
+     *         is {@link android.graphics.Bitmap.Config#HARDWARE}
+     *         and {@link BitmapFactory.Options#inMutable} is set.
      */
     public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
+        validate(opts);
         Bitmap bm;
 
         Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "decodeFileDescriptor");
diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java
index e689b08..04abca1 100644
--- a/graphics/java/android/graphics/BitmapRegionDecoder.java
+++ b/graphics/java/android/graphics/BitmapRegionDecoder.java
@@ -178,8 +178,12 @@
      *             inPurgeable is not supported.
      * @return The decoded bitmap, or null if the image data could not be
      *         decoded.
+     * @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
+     *         is {@link android.graphics.Bitmap.Config#HARDWARE}
+     *         and {@link BitmapFactory.Options#inMutable} is set.
      */
     public Bitmap decodeRegion(Rect rect, BitmapFactory.Options options) {
+        BitmapFactory.Options.validate(options);
         synchronized (mNativeLock) {
             checkRecycled("decodeRegion called on recycled region decoder");
             if (rect.right <= 0 || rect.bottom <= 0 || rect.left >= getWidth()
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 7dc5de3..d968516 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -1671,6 +1671,28 @@
     }
 
     /**
+     * Converts values from CIE xyY to CIE L*u*v*. Y is assumed to be 1 so the
+     * input xyY array only contains the x and y components. After this method
+     * returns, the xyY array contains the converted u and v components.
+     *
+     * @param xyY The xyY value to convert to XYZ, cannot be null,
+     *            length must be a multiple of 2
+     */
+    private static void xyYToUv(@NonNull @Size(multiple = 2) float[] xyY) {
+        for (int i = 0; i < xyY.length; i += 2) {
+            float x = xyY[i];
+            float y = xyY[i + 1];
+
+            float d = -2.0f * x + 12.0f * y + 3;
+            float u = (4.0f * x) / d;
+            float v = (9.0f * y) / d;
+
+            xyY[i] = u;
+            xyY[i + 1] = v;
+        }
+    }
+
+    /**
      * <p>Computes the chromatic adaptation transform from the specified
      * source white point to the specified destination white point.</p>
      *
@@ -3162,10 +3184,10 @@
     /**
      * <p>A color space renderer can be used to visualize and compare the gamut and
      * white point of one or more color spaces. The output is an sRGB {@link Bitmap}
-     * showing a CIE 1931 xyY chromaticity diagram.</p>
+     * showing a CIE 1931 xyY or a CIE 1976 UCS chromaticity diagram.</p>
      *
      * <p>The following code snippet shows how to compare the {@link Named#SRGB}
-     * and {@link Named#DCI_P3} color spaces:</p>
+     * and {@link Named#DCI_P3} color spaces in a CIE 1931 diagram:</p>
      *
      * <pre class="prettyprint">
      * Bitmap bitmap = ColorSpace.createRenderer()
@@ -3188,12 +3210,18 @@
      */
     public static class Renderer {
         private static final int NATIVE_SIZE = 1440;
+        private static final float UCS_SCALE = 9.0f / 6.0f;
+
+        // Number of subdivision of the inside of the spectral locus
+        private static final int CHROMATICITY_RESOLUTION = 32;
+        private static final double ONE_THIRD = 1.0 / 3.0;
 
         @IntRange(from = 128, to = Integer.MAX_VALUE)
         private int mSize = 1024;
 
         private boolean mShowWhitePoint = true;
         private boolean mClip = false;
+        private boolean mUcs = false;
 
         private final List<Pair<ColorSpace, Integer>> mColorSpaces = new ArrayList<>(2);
         private final List<Point> mPoints = new ArrayList<>(0);
@@ -3241,6 +3269,35 @@
         }
 
         /**
+         * <p>Defines whether the chromaticity diagram should use the uniform
+         * chromaticity scale (CIE 1976 UCS). When the uniform chromaticity scale
+         * is used, the distance between two points on the diagram is approximately
+         * proportional to the perceived color difference.</p>
+         *
+         * <p>The following code snippet shows how to enable the uniform chromaticity
+         * scale. The image below shows the result:</p>
+         * <pre class="prettyprint">
+         * Bitmap bitmap = ColorSpace.createRenderer()
+         *     .uniformChromaticityScale(true)
+         *     .add(ColorSpace.get(ColorSpace.Named.SRGB), 0xffffffff)
+         *     .add(ColorSpace.get(ColorSpace.Named.DCI_P3), 0xffffc845)
+         *     .render();
+         * </pre>
+         * <p>
+         *     <img src="{@docRoot}reference/android/images/graphics/colorspace_ucs.png" />
+         *     <figcaption style="text-align: center;">CIE 1976 UCS diagram</figcaption>
+         * </p>
+         *
+         * @param ucs True to render the chromaticity diagram as the CIE 1976 UCS diagram
+         * @return This instance of {@link Renderer}
+         */
+        @NonNull
+        public Renderer uniformChromaticityScale(boolean ucs) {
+            mUcs = ucs;
+            return this;
+        }
+
+        /**
          * Sets the dimensions (width and height) in pixels of the output bitmap.
          * The size must be at least 128px and defaults to 1024px.
          *
@@ -3302,7 +3359,7 @@
          * </pre>
          * <p>
          *     <img src="{@docRoot}reference/android/images/graphics/colorspace_comparison2.png" />
-         *     <figcaption style="text-align: center;">sRGB vs DCI-P3</figcaption>
+         *     <figcaption style="text-align: center;">sRGB, DCI-P3, ACES and scRGB</figcaption>
          * </p>
          *
          * @param colorSpace The color space whose gamut to render on the diagram
@@ -3385,6 +3442,7 @@
 
             setTransform(canvas, width, height, primaries);
             drawBox(canvas, width, height, paint, path);
+            setUcsTransform(canvas, height);
             drawLocus(canvas, width, height, paint, path, primaries);
             drawGamuts(canvas, width, height, paint, path, primaries, whitePoint);
             drawPoints(canvas, width, height, paint);
@@ -3406,7 +3464,11 @@
 
             paint.setStyle(Paint.Style.FILL);
 
+            float radius = 4.0f / (mUcs ? UCS_SCALE : 1.0f);
+
             float[] v = new float[3];
+            float[] xy = new float[2];
+
             for (final Point point : mPoints) {
                 v[0] = point.mRgb[0];
                 v[1] = point.mRgb[1];
@@ -3415,10 +3477,13 @@
 
                 paint.setColor(point.mColor);
 
-                // XYZ to xyY, assuming Y=1.0
+                // XYZ to xyY, assuming Y=1.0, then to L*u*v* if needed
                 float sum = v[0] + v[1] + v[2];
-                canvas.drawCircle(width * v[0] / sum, height - height * v[1] / sum,
-                        4.0f, paint);
+                xy[0] = v[0] / sum;
+                xy[1] = v[1] / sum;
+                if (mUcs) xyYToUv(xy);
+
+                canvas.drawCircle(width * xy[0], height - height * xy[1], radius, paint);
             }
         }
 
@@ -3440,6 +3505,8 @@
                 @NonNull Paint paint, @NonNull Path path,
                 @NonNull @Size(6) float[] primaries, @NonNull @Size(2) float[] whitePoint) {
 
+            float radius = 4.0f / (mUcs ? UCS_SCALE : 1.0f);
+
             for (final Pair<ColorSpace, Integer> item : mColorSpaces) {
                 ColorSpace colorSpace = item.first;
                 int color = item.second;
@@ -3447,7 +3514,7 @@
                 if (colorSpace.getModel() != Model.RGB) continue;
 
                 Rgb rgb = (Rgb) colorSpace;
-                getPrimaries(rgb, primaries);
+                getPrimaries(rgb, primaries, mUcs);
 
                 path.rewind();
                 path.moveTo(width * primaries[0], height - height * primaries[1]);
@@ -3462,11 +3529,12 @@
                 // Draw the white point
                 if (mShowWhitePoint) {
                     rgb.getWhitePoint(whitePoint);
+                    if (mUcs) xyYToUv(whitePoint);
 
                     paint.setStyle(Paint.Style.FILL);
                     paint.setColor(color);
-                    canvas.drawCircle(width * whitePoint[0], height - height * whitePoint[1],
-                            4.0f, paint);
+                    canvas.drawCircle(
+                            width * whitePoint[0], height - height * whitePoint[1], radius, paint);
                 }
             }
         }
@@ -3477,10 +3545,12 @@
          *
          * @param rgb The color space whose primaries to extract
          * @param primaries A pre-allocated array of 6 floats that will hold the result
+         * @param asUcs True if the primaries should be returned in Luv, false for xyY
          */
         @NonNull
         @Size(6)
-        private static float[] getPrimaries(@NonNull Rgb rgb, @NonNull @Size(6) float[] primaries) {
+        private static float[] getPrimaries(@NonNull Rgb rgb,
+                @NonNull @Size(6) float[] primaries, boolean asUcs) {
             // TODO: We should find a better way to handle these cases
             if (rgb.equals(ColorSpace.get(Named.EXTENDED_SRGB)) ||
                     rgb.equals(ColorSpace.get(Named.LINEAR_EXTENDED_SRGB))) {
@@ -3490,9 +3560,11 @@
                 primaries[3] = 1.24f;
                 primaries[4] = -0.23f;
                 primaries[5] = -0.57f;
-                return primaries;
+            } else {
+                rgb.getPrimaries(primaries);
             }
-            return rgb.getPrimaries(primaries);
+            if (asUcs) xyYToUv(primaries);
+            return primaries;
         }
 
         /**
@@ -3513,7 +3585,13 @@
             int vertexCount = SPECTRUM_LOCUS_X.length * CHROMATICITY_RESOLUTION * 6;
             float[] vertices = new float[vertexCount * 2];
             int[] colors = new int[vertices.length];
-            computeChromaticityMesh(NATIVE_SIZE, NATIVE_SIZE, vertices, colors);
+            computeChromaticityMesh(vertices, colors);
+
+            if (mUcs) xyYToUv(vertices);
+            for (int i = 0; i < vertices.length; i += 2) {
+                vertices[i] *= width;
+                vertices[i + 1] = height - vertices[i + 1] * height;
+            }
 
             // Draw the spectral locus
             if (mClip && mColorSpaces.size() > 0) {
@@ -3522,7 +3600,8 @@
                     if (colorSpace.getModel() != Model.RGB) continue;
 
                     Rgb rgb = (Rgb) colorSpace;
-                    getPrimaries(rgb, primaries);
+                    getPrimaries(rgb, primaries, mUcs);
+
                     break;
                 }
 
@@ -3559,6 +3638,7 @@
             }
             path.close();
 
+            paint.setStrokeWidth(4.0f / (mUcs ? UCS_SCALE : 1.0f));
             paint.setStyle(Paint.Style.STROKE);
             paint.setColor(0xff000000);
             canvas.drawPath(path, paint);
@@ -3576,25 +3656,38 @@
          */
         private void drawBox(@NonNull Canvas canvas, int width, int height, @NonNull Paint paint,
                 @NonNull Path path) {
+
+            int lineCount = 10;
+            float scale = 1.0f;
+            if (mUcs) {
+                lineCount = 7;
+                scale = UCS_SCALE;
+            }
+
             // Draw the unit grid
             paint.setStyle(Paint.Style.STROKE);
             paint.setStrokeWidth(2.0f);
             paint.setColor(0xffc0c0c0);
-            for (int i = 1; i <= 9; i++) {
-                canvas.drawLine(0.0f, height - (height * i / 10.0f),
-                        0.9f * width, height - (height * i / 10.0f), paint);
-                canvas.drawLine(width * i / 10.0f, height,
-                        width * i / 10.0f, 0.1f * height, paint);
+
+            for (int i = 1; i < lineCount - 1; i++) {
+                float v = i / 10.0f;
+                float x = (width * v) * scale;
+                float y = height - (height * v) * scale;
+
+                canvas.drawLine(0.0f, y, 0.9f * width, y, paint);
+                canvas.drawLine(x, height, x, 0.1f * height, paint);
             }
 
             // Draw tick marks
             paint.setStrokeWidth(4.0f);
             paint.setColor(0xff000000);
-            for (int i = 1; i <= 9; i++) {
-                canvas.drawLine(0.0f, height - (height * i / 10.0f),
-                        width / 100.0f, height - (height * i / 10.0f), paint);
-                canvas.drawLine(width * i / 10.0f, height,
-                        width * i / 10.0f, height - (height / 100.0f), paint);
+            for (int i = 1; i < lineCount - 1; i++) {
+                float v = i / 10.0f;
+                float x = (width * v) * scale;
+                float y = height - (height * v) * scale;
+
+                canvas.drawLine(0.0f, y, width / 100.0f, y, paint);
+                canvas.drawLine(x, height, x, height - (height / 100.0f), paint);
             }
 
             // Draw the axis labels
@@ -3603,14 +3696,15 @@
             paint.setTypeface(Typeface.create("sans-serif-light", Typeface.NORMAL));
 
             Rect bounds = new Rect();
-            for (int i = 1; i < 9; i++) {
+            for (int i = 1; i < lineCount - 1; i++) {
                 String text = "0." + i;
                 paint.getTextBounds(text, 0, text.length(), bounds);
 
-                float y = height - (height * i / 10.0f);
-                canvas.drawText(text, -0.05f * width + 10, y + bounds.height() / 2.0f, paint);
+                float v = i / 10.0f;
+                float x = (width * v) * scale;
+                float y = height - (height * v) * scale;
 
-                float x = width * i / 10.0f;
+                canvas.drawText(text, -0.05f * width + 10, y + bounds.height() / 2.0f, paint);
                 canvas.drawText(text, x - bounds.width() / 2.0f,
                         height + bounds.height() + 16, paint);
             }
@@ -3643,7 +3737,7 @@
                 if (colorSpace.getModel() != Model.RGB) continue;
 
                 Rgb rgb = (Rgb) colorSpace;
-                getPrimaries(rgb, primaries);
+                getPrimaries(rgb, primaries, mUcs);
 
                 primariesBounds.left = Math.min(primariesBounds.left, primaries[4]);
                 primariesBounds.top = Math.min(primariesBounds.top, primaries[5]);
@@ -3651,26 +3745,42 @@
                 primariesBounds.bottom = Math.max(primariesBounds.bottom, primaries[3]);
             }
 
+            float max = mUcs ? 0.6f : 0.9f;
+
             primariesBounds.left = Math.min(0.0f, primariesBounds.left);
             primariesBounds.top = Math.min(0.0f, primariesBounds.top);
-            primariesBounds.right = Math.max(0.9f, primariesBounds.right);
-            primariesBounds.bottom = Math.max(0.9f, primariesBounds.bottom);
+            primariesBounds.right = Math.max(max, primariesBounds.right);
+            primariesBounds.bottom = Math.max(max, primariesBounds.bottom);
 
-            float scaleX = 0.9f / primariesBounds.width();
-            float scaleY = 0.9f / primariesBounds.height();
+            float scaleX = max / primariesBounds.width();
+            float scaleY = max / primariesBounds.height();
             float scale = Math.min(scaleX, scaleY);
 
             canvas.scale(mSize / (float) NATIVE_SIZE, mSize / (float) NATIVE_SIZE);
             canvas.scale(scale, scale);
             canvas.translate(
-                    (primariesBounds.width() - 0.9f) * width / 2.0f,
-                    (primariesBounds.height() - 0.9f) * height / 2.0f);
+                    (primariesBounds.width() - max) * width / 2.0f,
+                    (primariesBounds.height() - max) * height / 2.0f);
 
             // The spectrum extends ~0.85 vertically and ~0.65 horizontally
             // We shift the canvas a little bit to get nicer margins
             canvas.translate(0.05f * width, -0.05f * height);
         }
 
+        /**
+         * Computes and applies the Canvas transforms required to render the CIE
+         * 197 UCS chromaticity diagram.
+         *
+         * @param canvas The canvas to transform
+         * @param height Height in pixel of the final image
+         */
+        private void setUcsTransform(@NonNull Canvas canvas, int height) {
+            if (mUcs) {
+                canvas.translate(0.0f, (height - height * UCS_SCALE));
+                canvas.scale(UCS_SCALE, UCS_SCALE);
+            }
+        }
+
         // X coordinates of the spectral locus in CIE 1931
         private static final float[] SPECTRUM_LOCUS_X = {
                 0.175596f, 0.172787f, 0.170806f, 0.170085f, 0.160343f,
@@ -3716,21 +3826,15 @@
                 0.037799f, 0.029673f, 0.021547f, 0.013421f, 0.005295f
         };
 
-        // Number of subdivision of the inside of the spectral locus
-        private static final int CHROMATICITY_RESOLUTION = 32;
-        private static final double ONE_THIRD = 1.0 / 3.0;
-
         /**
          * Computes a 2D mesh representation of the CIE 1931 chromaticity
          * diagram.
          *
-         * @param width Width in pixels of the mesh
-         * @param height Height in pixels of the mesh
          * @param vertices Array of floats that will hold the mesh vertices
          * @param colors Array of floats that will hold the mesh colors
          */
-        private static void computeChromaticityMesh(int width, int height,
-                @NonNull float[] vertices, @NonNull int[] colors) {
+        private static void computeChromaticityMesh(@NonNull float[] vertices,
+                @NonNull int[] colors) {
 
             ColorSpace colorSpace = get(Named.SRGB);
 
@@ -3796,18 +3900,18 @@
                     colorIndex += 6;
 
                     // Flip the mesh upside down to match Canvas' coordinates system
-                    vertices[vertexIndex++] = v1x * width;
-                    vertices[vertexIndex++] = height - v1y * height;
-                    vertices[vertexIndex++] = v2x * width;
-                    vertices[vertexIndex++] = height - v2y * height;
-                    vertices[vertexIndex++] = v3x * width;
-                    vertices[vertexIndex++] = height - v3y * height;
-                    vertices[vertexIndex++] = v1x * width;
-                    vertices[vertexIndex++] = height - v1y * height;
-                    vertices[vertexIndex++] = v3x * width;
-                    vertices[vertexIndex++] = height - v3y * height;
-                    vertices[vertexIndex++] = v4x * width;
-                    vertices[vertexIndex++] = height - v4y * height;
+                    vertices[vertexIndex++] = v1x;
+                    vertices[vertexIndex++] = v1y;
+                    vertices[vertexIndex++] = v2x;
+                    vertices[vertexIndex++] = v2y;
+                    vertices[vertexIndex++] = v3x;
+                    vertices[vertexIndex++] = v3y;
+                    vertices[vertexIndex++] = v1x;
+                    vertices[vertexIndex++] = v1y;
+                    vertices[vertexIndex++] = v3x;
+                    vertices[vertexIndex++] = v3y;
+                    vertices[vertexIndex++] = v4x;
+                    vertices[vertexIndex++] = v4y;
                 }
             }
         }
diff --git a/graphics/java/android/graphics/LayerRasterizer.java b/graphics/java/android/graphics/LayerRasterizer.java
index b692ecf..25155ab 100644
--- a/graphics/java/android/graphics/LayerRasterizer.java
+++ b/graphics/java/android/graphics/LayerRasterizer.java
@@ -16,26 +16,20 @@
 
 package android.graphics;
 
+/**
+ * @removed feature is not supported by hw-accerlerated or PDF backends
+ */
 @Deprecated
 public class LayerRasterizer extends Rasterizer {
-    public LayerRasterizer() {
-        native_instance = nativeConstructor();
-    }
+    public LayerRasterizer() { }
 
     /** Add a new layer (above any previous layers) to the rasterizer.
         The layer will extract those fields that affect the mask from
         the specified paint, but will not retain a reference to the paint
         object itself, so it may be reused without danger of side-effects.
     */
-    public void addLayer(Paint paint, float dx, float dy) {
-        nativeAddLayer(native_instance, paint.getNativeInstance(), dx, dy);
-    }
+    public void addLayer(Paint paint, float dx, float dy) { }
 
-    public void addLayer(Paint paint) {
-        nativeAddLayer(native_instance, paint.getNativeInstance(), 0, 0);
-    }
-
-    private static native long nativeConstructor();
-    private static native void nativeAddLayer(long native_layer, long native_paint, float dx, float dy);
+    public void addLayer(Paint paint) { }
 }
 
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index aa81b91..3e59f34 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -58,8 +58,12 @@
     @Mode
     public int mMode = MODE_EMPTY;
 
-    /** @hide */
-    public final Path mPath = new Path();
+    /**
+     * Only guaranteed to be non-null when mode == MODE_CONVEX_PATH
+     *
+     * @hide
+     */
+    public Path mPath;
 
     /** @hide */
     public final Rect mRect = new Rect();
@@ -87,8 +91,11 @@
      * @see #isEmpty()
      */
     public void setEmpty() {
+        if (mPath != null) {
+            // rewind here to avoid thrashing the allocations, but could alternately clear ref
+            mPath.rewind();
+        }
         mMode = MODE_EMPTY;
-        mPath.rewind();
         mRect.setEmpty();
         mRadius = RADIUS_UNDEFINED;
     }
@@ -148,7 +155,12 @@
      */
     public void set(@NonNull Outline src) {
         mMode = src.mMode;
-        mPath.set(src.mPath);
+        if (src.mMode == MODE_CONVEX_PATH) {
+            if (mPath == null) {
+                mPath = new Path();
+            }
+            mPath.set(src.mPath);
+        }
         mRect.set(src.mRect);
         mRadius = src.mRadius;
         mAlpha = src.mAlpha;
@@ -180,10 +192,13 @@
             return;
         }
 
+        if (mMode == MODE_CONVEX_PATH) {
+            // rewind here to avoid thrashing the allocations, but could alternately clear ref
+            mPath.rewind();
+        }
         mMode = MODE_ROUND_RECT;
         mRect.set(left, top, right, bottom);
         mRadius = radius;
-        mPath.rewind();
     }
 
     /**
@@ -236,8 +251,13 @@
             return;
         }
 
+        if (mPath == null) {
+            mPath = new Path();
+        } else {
+            mPath.rewind();
+        }
+
         mMode = MODE_CONVEX_PATH;
-        mPath.rewind();
         mPath.addOval(left, top, right, bottom, Path.Direction.CW);
         mRect.setEmpty();
         mRadius = RADIUS_UNDEFINED;
@@ -264,6 +284,10 @@
             throw new IllegalArgumentException("path must be convex");
         }
 
+        if (mPath == null) {
+            mPath = new Path();
+        }
+
         mMode = MODE_CONVEX_PATH;
         mPath.set(convexPath);
         mRect.setEmpty();
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 554e5d2..fc873c4 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -61,7 +61,6 @@
     private ColorFilter mColorFilter;
     private MaskFilter  mMaskFilter;
     private PathEffect  mPathEffect;
-    private Rasterizer  mRasterizer;
     private Shader      mShader;
     private Typeface    mTypeface;
     private Xfermode    mXfermode;
@@ -494,7 +493,6 @@
         mColorFilter = null;
         mMaskFilter = null;
         mPathEffect = null;
-        mRasterizer = null;
         mShader = null;
         mNativeShader = 0;
         mTypeface = null;
@@ -532,7 +530,6 @@
         mColorFilter = paint.mColorFilter;
         mMaskFilter = paint.mMaskFilter;
         mPathEffect = paint.mPathEffect;
-        mRasterizer = paint.mRasterizer;
         mShader = paint.mShader;
         mNativeShader = paint.mNativeShader;
         mTypeface = paint.mTypeface;
@@ -1164,11 +1161,12 @@
      *
      * @return         the paint's rasterizer (or null)
      *
-     *  @deprecated Rasterizer is not supported by either the HW or PDF backends.
+     * @deprecated Rasterizer is not supported by either the HW or PDF backends.
+     * @removed
      */
     @Deprecated
     public Rasterizer getRasterizer() {
-        return mRasterizer;
+        return null;
     }
 
     /**
@@ -1181,16 +1179,11 @@
      *                   the paint.
      * @return           rasterizer
      *
-     *  @deprecated Rasterizer is not supported by either the HW or PDF backends.
+     * @deprecated Rasterizer is not supported by either the HW or PDF backends.
+     * @removed
      */
     @Deprecated
     public Rasterizer setRasterizer(Rasterizer rasterizer) {
-        long rasterizerNative = 0;
-        if (rasterizer != null) {
-            rasterizerNative = rasterizer.native_instance;
-        }
-        nSetRasterizer(mNativePaint, rasterizerNative);
-        mRasterizer = rasterizer;
         return rasterizer;
     }
 
@@ -2715,8 +2708,6 @@
     @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);
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index 4ed2581..3631373 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -19,6 +19,9 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 
+import dalvik.annotation.optimization.CriticalNative;
+import dalvik.annotation.optimization.FastNative;
+
 /**
  * The Path class encapsulates compound (multiple contour) geometric paths
  * consisting of straight line segments, quadratic curves, and cubic curves.
@@ -46,7 +49,7 @@
      * Create an empty path
      */
     public Path() {
-        mNativePath = init1();
+        mNativePath = nInit();
     }
 
     /**
@@ -63,7 +66,7 @@
                 rects = new Region(src.rects);
             }
         }
-        mNativePath = init2(valNative);
+        mNativePath = nInit(valNative);
     }
 
     /**
@@ -77,7 +80,7 @@
         // We promised not to change this, so preserve it around the native
         // call, which does now reset fill type.
         final FillType fillType = getFillType();
-        native_reset(mNativePath);
+        nReset(mNativePath);
         setFillType(fillType);
     }
 
@@ -89,7 +92,7 @@
         isSimplePath = true;
         mLastDirection = null;
         if (rects != null) rects.setEmpty();
-        native_rewind(mNativePath);
+        nRewind(mNativePath);
     }
 
     /** Replace the contents of this with the contents of src.
@@ -99,7 +102,7 @@
             return;
         }
         isSimplePath = src.isSimplePath;
-        native_set(mNativePath, src.mNativePath);
+        nSet(mNativePath, src.mNativePath);
         if (!isSimplePath) {
             return;
         }
@@ -174,7 +177,7 @@
      * @see #op(Path, android.graphics.Path.Op)
      */
     public boolean op(Path path1, Path path2, Op op) {
-        if (native_op(path1.mNativePath, path2.mNativePath, op.ordinal(), this.mNativePath)) {
+        if (nOp(path1.mNativePath, path2.mNativePath, op.ordinal(), this.mNativePath)) {
             isSimplePath = false;
             rects = null;
             return true;
@@ -194,7 +197,7 @@
      * @return True if the path is convex.
      */
     public boolean isConvex() {
-        return native_isConvex(mNativePath);
+        return nIsConvex(mNativePath);
     }
 
     /**
@@ -243,7 +246,7 @@
      * @return the path's fill type
      */
     public FillType getFillType() {
-        return sFillTypeArray[native_getFillType(mNativePath)];
+        return sFillTypeArray[nGetFillType(mNativePath)];
     }
 
     /**
@@ -252,7 +255,7 @@
      * @param ft The new fill type for this path
      */
     public void setFillType(FillType ft) {
-        native_setFillType(mNativePath, ft.nativeInt);
+        nSetFillType(mNativePath, ft.nativeInt);
     }
 
     /**
@@ -261,7 +264,7 @@
      * @return true if the filltype is one of the INVERSE variants
      */
     public boolean isInverseFillType() {
-        final int ft = native_getFillType(mNativePath);
+        final int ft = nGetFillType(mNativePath);
         return (ft & FillType.INVERSE_WINDING.nativeInt) != 0;
     }
 
@@ -269,9 +272,9 @@
      * Toggles the INVERSE state of the filltype
      */
     public void toggleInverseFillType() {
-        int ft = native_getFillType(mNativePath);
+        int ft = nGetFillType(mNativePath);
         ft ^= FillType.INVERSE_WINDING.nativeInt;
-        native_setFillType(mNativePath, ft);
+        nSetFillType(mNativePath, ft);
     }
 
     /**
@@ -280,7 +283,7 @@
      * @return true if the path is empty (contains no lines or curves)
      */
     public boolean isEmpty() {
-        return native_isEmpty(mNativePath);
+        return nIsEmpty(mNativePath);
     }
 
     /**
@@ -293,7 +296,7 @@
      * @return     true if the path specifies a rectangle
      */
     public boolean isRect(RectF rect) {
-        return native_isRect(mNativePath, rect);
+        return nIsRect(mNativePath, rect);
     }
 
     /**
@@ -306,7 +309,7 @@
      */
     @SuppressWarnings({"UnusedDeclaration"})
     public void computeBounds(RectF bounds, boolean exact) {
-        native_computeBounds(mNativePath, bounds);
+        nComputeBounds(mNativePath, bounds);
     }
 
     /**
@@ -317,7 +320,7 @@
      *                     path
      */
     public void incReserve(int extraPtCount) {
-        native_incReserve(mNativePath, extraPtCount);
+        nIncReserve(mNativePath, extraPtCount);
     }
 
     /**
@@ -327,7 +330,7 @@
      * @param y The y-coordinate of the start of a new contour
      */
     public void moveTo(float x, float y) {
-        native_moveTo(mNativePath, x, y);
+        nMoveTo(mNativePath, x, y);
     }
 
     /**
@@ -341,7 +344,7 @@
      *           previous contour, to specify the start of a new contour
      */
     public void rMoveTo(float dx, float dy) {
-        native_rMoveTo(mNativePath, dx, dy);
+        nRMoveTo(mNativePath, dx, dy);
     }
 
     /**
@@ -354,7 +357,7 @@
      */
     public void lineTo(float x, float y) {
         isSimplePath = false;
-        native_lineTo(mNativePath, x, y);
+        nLineTo(mNativePath, x, y);
     }
 
     /**
@@ -369,7 +372,7 @@
      */
     public void rLineTo(float dx, float dy) {
         isSimplePath = false;
-        native_rLineTo(mNativePath, dx, dy);
+        nRLineTo(mNativePath, dx, dy);
     }
 
     /**
@@ -384,7 +387,7 @@
      */
     public void quadTo(float x1, float y1, float x2, float y2) {
         isSimplePath = false;
-        native_quadTo(mNativePath, x1, y1, x2, y2);
+        nQuadTo(mNativePath, x1, y1, x2, y2);
     }
 
     /**
@@ -403,7 +406,7 @@
      */
     public void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
         isSimplePath = false;
-        native_rQuadTo(mNativePath, dx1, dy1, dx2, dy2);
+        nRQuadTo(mNativePath, dx1, dy1, dx2, dy2);
     }
 
     /**
@@ -421,7 +424,7 @@
     public void cubicTo(float x1, float y1, float x2, float y2,
                         float x3, float y3) {
         isSimplePath = false;
-        native_cubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
+        nCubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
     }
 
     /**
@@ -432,7 +435,7 @@
     public void rCubicTo(float x1, float y1, float x2, float y2,
                          float x3, float y3) {
         isSimplePath = false;
-        native_rCubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
+        nRCubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
     }
 
     /**
@@ -483,7 +486,7 @@
     public void arcTo(float left, float top, float right, float bottom, float startAngle,
             float sweepAngle, boolean forceMoveTo) {
         isSimplePath = false;
-        native_arcTo(mNativePath, left, top, right, bottom, startAngle, sweepAngle, forceMoveTo);
+        nArcTo(mNativePath, left, top, right, bottom, startAngle, sweepAngle, forceMoveTo);
     }
 
     /**
@@ -492,7 +495,7 @@
      */
     public void close() {
         isSimplePath = false;
-        native_close(mNativePath);
+        nClose(mNativePath);
     }
 
     /**
@@ -544,7 +547,7 @@
      */
     public void addRect(float left, float top, float right, float bottom, Direction dir) {
         detectSimplePath(left, top, right, bottom, dir);
-        native_addRect(mNativePath, left, top, right, bottom, dir.nativeInt);
+        nAddRect(mNativePath, left, top, right, bottom, dir.nativeInt);
     }
 
     /**
@@ -564,7 +567,7 @@
      */
     public void addOval(float left, float top, float right, float bottom, Direction dir) {
         isSimplePath = false;
-        native_addOval(mNativePath, left, top, right, bottom, dir.nativeInt);
+        nAddOval(mNativePath, left, top, right, bottom, dir.nativeInt);
     }
 
     /**
@@ -577,7 +580,7 @@
      */
     public void addCircle(float x, float y, float radius, Direction dir) {
         isSimplePath = false;
-        native_addCircle(mNativePath, x, y, radius, dir.nativeInt);
+        nAddCircle(mNativePath, x, y, radius, dir.nativeInt);
     }
 
     /**
@@ -600,7 +603,7 @@
     public void addArc(float left, float top, float right, float bottom, float startAngle,
             float sweepAngle) {
         isSimplePath = false;
-        native_addArc(mNativePath, left, top, right, bottom, startAngle, sweepAngle);
+        nAddArc(mNativePath, left, top, right, bottom, startAngle, sweepAngle);
     }
 
     /**
@@ -625,7 +628,7 @@
     public void addRoundRect(float left, float top, float right, float bottom, float rx, float ry,
             Direction dir) {
         isSimplePath = false;
-        native_addRoundRect(mNativePath, left, top, right, bottom, rx, ry, dir.nativeInt);
+        nAddRoundRect(mNativePath, left, top, right, bottom, rx, ry, dir.nativeInt);
     }
 
     /**
@@ -658,7 +661,7 @@
             throw new ArrayIndexOutOfBoundsException("radii[] needs 8 values");
         }
         isSimplePath = false;
-        native_addRoundRect(mNativePath, left, top, right, bottom, radii, dir.nativeInt);
+        nAddRoundRect(mNativePath, left, top, right, bottom, radii, dir.nativeInt);
     }
 
     /**
@@ -669,7 +672,7 @@
      */
     public void addPath(Path src, float dx, float dy) {
         isSimplePath = false;
-        native_addPath(mNativePath, src.mNativePath, dx, dy);
+        nAddPath(mNativePath, src.mNativePath, dx, dy);
     }
 
     /**
@@ -679,7 +682,7 @@
      */
     public void addPath(Path src) {
         isSimplePath = false;
-        native_addPath(mNativePath, src.mNativePath);
+        nAddPath(mNativePath, src.mNativePath);
     }
 
     /**
@@ -689,7 +692,7 @@
      */
     public void addPath(Path src, Matrix matrix) {
         if (!src.isSimplePath) isSimplePath = false;
-        native_addPath(mNativePath, src.mNativePath, matrix.native_instance);
+        nAddPath(mNativePath, src.mNativePath, matrix.native_instance);
     }
 
     /**
@@ -725,7 +728,7 @@
         } else {
             isSimplePath = false;
         }
-        native_offset(mNativePath, dx, dy);
+        nOffset(mNativePath, dx, dy);
     }
 
     /**
@@ -736,7 +739,7 @@
      */
     public void setLastPoint(float dx, float dy) {
         isSimplePath = false;
-        native_setLastPoint(mNativePath, dx, dy);
+        nSetLastPoint(mNativePath, dx, dy);
     }
 
     /**
@@ -753,7 +756,7 @@
             dst.isSimplePath = false;
             dstNative = dst.mNativePath;
         }
-        native_transform(mNativePath, matrix.native_instance, dstNative);
+        nTransform(mNativePath, matrix.native_instance, dstNative);
     }
 
     /**
@@ -763,12 +766,12 @@
      */
     public void transform(Matrix matrix) {
         isSimplePath = false;
-        native_transform(mNativePath, matrix.native_instance);
+        nTransform(mNativePath, matrix.native_instance);
     }
 
     protected void finalize() throws Throwable {
         try {
-            finalizer(mNativePath);
+            nFinalize(mNativePath);
             mNativePath = 0;  //  Other finalizers can still call us.
         } finally {
             super.finalize();
@@ -803,59 +806,68 @@
      * @return An array of components for points approximating the Path.
      */
     public float[] approximate(float acceptableError) {
-        return native_approximate(mNativePath, acceptableError);
+        return nApproximate(mNativePath, acceptableError);
     }
 
-    private static native long init1();
-    private static native long init2(long nPath);
-    private static native void native_reset(long nPath);
-    private static native void native_rewind(long nPath);
-    private static native void native_set(long native_dst, long native_src);
-    private static native boolean native_isConvex(long nPath);
-    private static native int native_getFillType(long nPath);
-    private static native void native_setFillType(long nPath, int ft);
-    private static native boolean native_isEmpty(long nPath);
-    private static native boolean native_isRect(long nPath, RectF rect);
-    private static native void native_computeBounds(long nPath, RectF bounds);
-    private static native void native_incReserve(long nPath, int extraPtCount);
-    private static native void native_moveTo(long nPath, float x, float y);
-    private static native void native_rMoveTo(long nPath, float dx, float dy);
-    private static native void native_lineTo(long nPath, float x, float y);
-    private static native void native_rLineTo(long nPath, float dx, float dy);
-    private static native void native_quadTo(long nPath, float x1, float y1,
-                                             float x2, float y2);
-    private static native void native_rQuadTo(long nPath, float dx1, float dy1,
-                                              float dx2, float dy2);
-    private static native void native_cubicTo(long nPath, float x1, float y1,
-                                        float x2, float y2, float x3, float y3);
-    private static native void native_rCubicTo(long nPath, float x1, float y1,
-                                        float x2, float y2, float x3, float y3);
-    private static native void native_arcTo(long nPath, float left, float top,
-                                            float right, float bottom, float startAngle,
-                                            float sweepAngle, boolean forceMoveTo);
-    private static native void native_close(long nPath);
-    private static native void native_addRect(long nPath, float left, float top,
-                                            float right, float bottom, int dir);
-    private static native void native_addOval(long nPath, float left, float top,
+    // ------------------ Regular JNI ------------------------
+
+    private static native long nInit();
+    private static native long nInit(long nPath);
+    private static native void nFinalize(long nPath);
+    private static native void nSet(long native_dst, long nSrc);
+    private static native void nComputeBounds(long nPath, RectF bounds);
+    private static native void nIncReserve(long nPath, int extraPtCount);
+    private static native void nMoveTo(long nPath, float x, float y);
+    private static native void nRMoveTo(long nPath, float dx, float dy);
+    private static native void nLineTo(long nPath, float x, float y);
+    private static native void nRLineTo(long nPath, float dx, float dy);
+    private static native void nQuadTo(long nPath, float x1, float y1, float x2, float y2);
+    private static native void nRQuadTo(long nPath, float dx1, float dy1, float dx2, float dy2);
+    private static native void nCubicTo(long nPath, float x1, float y1, float x2, float y2,
+            float x3, float y3);
+    private static native void nRCubicTo(long nPath, float x1, float y1, float x2, float y2,
+            float x3, float y3);
+    private static native void nArcTo(long nPath, float left, float top, float right, float bottom,
+            float startAngle, float sweepAngle, boolean forceMoveTo);
+    private static native void nClose(long nPath);
+    private static native void nAddRect(long nPath, float left, float top,
             float right, float bottom, int dir);
-    private static native void native_addCircle(long nPath, float x, float y, float radius, int dir);
-    private static native void native_addArc(long nPath, float left, float top,
-                                             float right, float bottom,
-                                             float startAngle, float sweepAngle);
-    private static native void native_addRoundRect(long nPath, float left, float top,
-                                                   float right, float bottom,
-                                                   float rx, float ry, int dir);
-    private static native void native_addRoundRect(long nPath, float left, float top,
-                                                   float right, float bottom,
-                                                   float[] radii, int dir);
-    private static native void native_addPath(long nPath, long src, float dx, float dy);
-    private static native void native_addPath(long nPath, long src);
-    private static native void native_addPath(long nPath, long src, long matrix);
-    private static native void native_offset(long nPath, float dx, float dy);
-    private static native void native_setLastPoint(long nPath, float dx, float dy);
-    private static native void native_transform(long nPath, long matrix, long dst_path);
-    private static native void native_transform(long nPath, long matrix);
-    private static native boolean native_op(long path1, long path2, int op, long result);
-    private static native void finalizer(long nPath);
-    private static native float[] native_approximate(long nPath, float error);
+    private static native void nAddOval(long nPath, float left, float top,
+            float right, float bottom, int dir);
+    private static native void nAddCircle(long nPath, float x, float y, float radius, int dir);
+    private static native void nAddArc(long nPath, float left, float top, float right, float bottom,
+            float startAngle, float sweepAngle);
+    private static native void nAddRoundRect(long nPath, float left, float top,
+            float right, float bottom, float rx, float ry, int dir);
+    private static native void nAddRoundRect(long nPath, float left, float top,
+            float right, float bottom, float[] radii, int dir);
+    private static native void nAddPath(long nPath, long src, float dx, float dy);
+    private static native void nAddPath(long nPath, long src);
+    private static native void nAddPath(long nPath, long src, long matrix);
+    private static native void nOffset(long nPath, float dx, float dy);
+    private static native void nSetLastPoint(long nPath, float dx, float dy);
+    private static native void nTransform(long nPath, long matrix, long dst_path);
+    private static native void nTransform(long nPath, long matrix);
+    private static native boolean nOp(long path1, long path2, int op, long result);
+    private static native float[] nApproximate(long nPath, float error);
+
+    // ------------------ Fast JNI ------------------------
+
+    @FastNative
+    private static native boolean nIsRect(long nPath, RectF rect);
+
+    // ------------------ Critical JNI ------------------------
+
+    @CriticalNative
+    private static native void nReset(long nPath);
+    @CriticalNative
+    private static native void nRewind(long nPath);
+    @CriticalNative
+    private static native boolean nIsEmpty(long nPath);
+    @CriticalNative
+    private static native boolean nIsConvex(long nPath);
+    @CriticalNative
+    private static native int nGetFillType(long nPath);
+    @CriticalNative
+    private static native void nSetFillType(long nPath, int ft);
 }
diff --git a/graphics/java/android/graphics/PixelFormat.java b/graphics/java/android/graphics/PixelFormat.java
index 98082ca..0fa52f8 100644
--- a/graphics/java/android/graphics/PixelFormat.java
+++ b/graphics/java/android/graphics/PixelFormat.java
@@ -22,13 +22,17 @@
 import java.lang.annotation.RetentionPolicy;
 
 public class PixelFormat {
-
     /** @hide */
     @IntDef({UNKNOWN, TRANSLUCENT, TRANSPARENT, OPAQUE})
     @Retention(RetentionPolicy.SOURCE)
     public @interface Opacity {}
 
-    /* these constants need to match those in hardware/hardware.h */
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({RGBA_8888, RGBX_8888, RGBA_F16, RGBX_F16, RGB_888, RGB_565})
+    public @interface Format { };
+
+    // NOTE: these constants must match the values from graphics/common/x.x/types.hal
 
     public static final int UNKNOWN     = 0;
 
@@ -62,7 +66,6 @@
     @Deprecated
     public static final int RGB_332     = 0xB;
 
-
     /**
      * @deprecated use {@link android.graphics.ImageFormat#NV16
      * ImageFormat.NV16} instead.
@@ -84,6 +87,9 @@
     @Deprecated
     public static final int YCbCr_422_I = 0x14;
 
+    public static final int RGBA_F16    = 0x16;
+    public static final int RGBX_F16    = 0x17;
+
     /**
      * @deprecated use {@link android.graphics.ImageFormat#JPEG
      * ImageFormat.JPEG} instead.
@@ -91,7 +97,10 @@
     @Deprecated
     public static final int JPEG        = 0x100;
 
-    public static void getPixelFormatInfo(int format, PixelFormat info) {
+    public int bytesPerPixel;
+    public int bitsPerPixel;
+
+    public static void getPixelFormatInfo(@Format int format, PixelFormat info) {
         switch (format) {
             case RGBA_8888:
             case RGBX_8888:
@@ -124,18 +133,24 @@
                 info.bitsPerPixel = 12;
                 info.bytesPerPixel = 1;
                 break;
+            case RGBA_F16:
+            case RGBX_F16:
+                info.bitsPerPixel = 64;
+                info.bytesPerPixel = 8;
+                break;
             default:
                 throw new IllegalArgumentException("unknown pixel format " + format);
         }
     }
 
-    public static boolean formatHasAlpha(int format) {
+    public static boolean formatHasAlpha(@Format int format) {
         switch (format) {
             case PixelFormat.A_8:
             case PixelFormat.LA_88:
             case PixelFormat.RGBA_4444:
             case PixelFormat.RGBA_5551:
             case PixelFormat.RGBA_8888:
+            case PixelFormat.RGBA_F16:
             case PixelFormat.TRANSLUCENT:
             case PixelFormat.TRANSPARENT:
                 return true;
@@ -143,9 +158,6 @@
         return false;
     }
 
-    public int  bytesPerPixel;
-    public int  bitsPerPixel;
-
     /**
      * Determine whether or not this is a public-visible and non-deprecated {@code format}.
      *
@@ -159,12 +171,14 @@
      *
      * @hide
      */
-    public static boolean isPublicFormat(int format) {
+    public static boolean isPublicFormat(@Format int format) {
         switch (format) {
             case RGBA_8888:
             case RGBX_8888:
             case RGB_888:
             case RGB_565:
+            case RGBA_F16:
+            case RGBX_F16:
                 return true;
         }
 
diff --git a/graphics/java/android/graphics/Rasterizer.java b/graphics/java/android/graphics/Rasterizer.java
index f6a38fe..29d82fa 100644
--- a/graphics/java/android/graphics/Rasterizer.java
+++ b/graphics/java/android/graphics/Rasterizer.java
@@ -21,15 +21,10 @@
 
 package android.graphics;
 
-@Deprecated
+/**
+ * @removed feature is not supported by hw-accerlerated or PDF backends
+ */
 public class Rasterizer {
 
-    protected void finalize() throws Throwable {
-        finalizer(native_instance);
-        native_instance = 0;
-    }
-
-    private static native void finalizer(long native_instance);
-
-    long native_instance;
+    protected void finalize() throws Throwable { }
 }
diff --git a/legacy-test/Android.mk b/legacy-test/Android.mk
index 7bab189..5e72a0d 100644
--- a/legacy-test/Android.mk
+++ b/legacy-test/Android.mk
@@ -25,7 +25,6 @@
 LOCAL_MODULE := legacy-test
 LOCAL_NO_STANDARD_LIBRARIES := true
 LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
-LOCAL_STATIC_JAVA_LIBRARIES := core-junit-static
 
 include $(BUILD_JAVA_LIBRARY)
 
diff --git a/legacy-test/src/junit/MODULE_LICENSE_CPL b/legacy-test/src/junit/MODULE_LICENSE_CPL
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/legacy-test/src/junit/MODULE_LICENSE_CPL
diff --git a/legacy-test/src/junit/README.android b/legacy-test/src/junit/README.android
new file mode 100644
index 0000000..1384a1f
--- /dev/null
+++ b/legacy-test/src/junit/README.android
@@ -0,0 +1,11 @@
+URL: https://github.com/junit-team/junit4
+License: Common Public License Version 1.0
+License File: cpl-v10.html
+
+This is JUnit 4.10 source that was previously part of the Android Public API.
+Where necessary it has been patched to be compatible (according to Android API
+requirements) with JUnit 3.8.
+
+These are copied here to ensure that the android.test.runner target remains
+compatible with the last version of the Android API (25) that contained these
+classes even when external/junit is upgraded to a later version.
diff --git a/legacy-test/src/junit/cpl-v10.html b/legacy-test/src/junit/cpl-v10.html
new file mode 100644
index 0000000..36aa208
--- /dev/null
+++ b/legacy-test/src/junit/cpl-v10.html
@@ -0,0 +1,125 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
+<HTML>
+<HEAD>
+<TITLE>Common Public License - v 1.0</TITLE>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</HEAD>
+
+<BODY BGCOLOR="#FFFFFF" VLINK="#800000">
+
+
+<P ALIGN="CENTER"><B>Common Public License - v 1.0</B>
+<P><B></B><FONT SIZE="3"></FONT>
+<P><FONT SIZE="3"></FONT><FONT SIZE="2">THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC LICENSE ("AGREEMENT").  ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.</FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"><B>1.  DEFINITIONS</B></FONT>
+<P><FONT SIZE="2">"Contribution" means:</FONT>
+
+<UL><FONT SIZE="2">a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and<BR CLEAR="LEFT">
+b) in the case of each subsequent Contributor:</FONT></UL>
+
+
+<UL><FONT SIZE="2">i)	 	changes to the Program, and</FONT></UL>
+
+
+<UL><FONT SIZE="2">ii)		additions to the Program;</FONT></UL>
+
+
+<UL><FONT SIZE="2">where such changes and/or additions to the Program originate from and are distributed by that particular Contributor.  </FONT><FONT SIZE="2">A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf.  </FONT><FONT SIZE="2">Contributions do not include additions to the Program which:  (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.  </FONT></UL>
+
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">"Contributor" means any person or entity that distributes the Program.</FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">"Licensed Patents " mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.  </FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2">"Program" means the Contributions distributed in accordance with this Agreement.</FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.</FONT>
+<P><FONT SIZE="2"><B></B></FONT>
+<P><FONT SIZE="2"><B>2.  GRANT OF RIGHTS</B></FONT>
+
+<UL><FONT SIZE="2"></FONT><FONT SIZE="2">a)	</FONT><FONT SIZE="2">Subject to the terms of this Agreement, each Contributor hereby grants</FONT><FONT SIZE="2"> Recipient a non-exclusive, worldwide, royalty-free copyright license to</FONT><FONT SIZE="2" COLOR="#FF0000"> </FONT><FONT SIZE="2">reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.</FONT></UL>
+
+
+<UL><FONT SIZE="2"></FONT></UL>
+
+
+<UL><FONT SIZE="2"></FONT><FONT SIZE="2">b) 	Subject to the terms of this Agreement, each Contributor hereby grants </FONT><FONT SIZE="2">Recipient a non-exclusive, worldwide,</FONT><FONT SIZE="2" COLOR="#008000"> </FONT><FONT SIZE="2">royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form.  This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents.  The patent license shall not apply to any other combinations which include the Contribution.  No hardware per se is licensed hereunder.   </FONT></UL>
+
+
+<UL><FONT SIZE="2"></FONT></UL>
+
+
+<UL><FONT SIZE="2">c)	Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity.  Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise.  As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any.  For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.</FONT></UL>
+
+
+<UL><FONT SIZE="2"></FONT></UL>
+
+
+<UL><FONT SIZE="2">d)	Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. </FONT></UL>
+
+
+<UL><FONT SIZE="2"></FONT></UL>
+
+<P><FONT SIZE="2"><B>3.  REQUIREMENTS</B></FONT>
+<P><FONT SIZE="2"><B></B>A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:</FONT>
+
+<UL><FONT SIZE="2">a)	it complies with the terms and conditions of this Agreement; and</FONT></UL>
+
+
+<UL><FONT SIZE="2">b)	its license agreement:</FONT></UL>
+
+
+<UL><FONT SIZE="2">i)	effectively disclaims</FONT><FONT SIZE="2"> on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; </FONT></UL>
+
+
+<UL><FONT SIZE="2">ii) 	effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; </FONT></UL>
+
+
+<UL><FONT SIZE="2">iii)</FONT><FONT SIZE="2">	states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and</FONT></UL>
+
+
+<UL><FONT SIZE="2">iv)	states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.</FONT><FONT SIZE="2" COLOR="#0000FF"> </FONT><FONT SIZE="2" COLOR="#FF0000"></FONT></UL>
+
+
+<UL><FONT SIZE="2" COLOR="#FF0000"></FONT><FONT SIZE="2"></FONT></UL>
+
+<P><FONT SIZE="2">When the Program is made available in source code form:</FONT>
+
+<UL><FONT SIZE="2">a)	it must be made available under this Agreement; and </FONT></UL>
+
+
+<UL><FONT SIZE="2">b)	a copy of this Agreement must be included with each copy of the Program.  </FONT></UL>
+
+<P><FONT SIZE="2"></FONT><FONT SIZE="2" COLOR="#0000FF"><STRIKE></STRIKE></FONT>
+<P><FONT SIZE="2" COLOR="#0000FF"><STRIKE></STRIKE></FONT><FONT SIZE="2">Contributors may not remove or alter any copyright notices contained within the Program.  </FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.  </FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"><B>4.  COMMERCIAL DISTRIBUTION</B></FONT>
+<P><FONT SIZE="2">Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like.  While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors.   Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering.  The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement.  In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations.  The Indemnified Contributor may participate in any such claim at its own expense.</FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">For example, a Contributor might include the Program in a commercial product offering, Product X.  That Contributor is then a Commercial Contributor.  If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone.  Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.</FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2" COLOR="#0000FF"></FONT>
+<P><FONT SIZE="2" COLOR="#0000FF"></FONT><FONT SIZE="2"><B>5.  NO WARRANTY</B></FONT>
+<P><FONT SIZE="2">EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is</FONT><FONT SIZE="2"> solely responsible for determining the appropriateness of using and distributing </FONT><FONT SIZE="2">the Program</FONT><FONT SIZE="2"> and assumes all risks associated with its exercise of rights under this Agreement</FONT><FONT SIZE="2">, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, </FONT><FONT SIZE="2">programs or equipment, and unavailability or interruption of operations</FONT><FONT SIZE="2">.  </FONT><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2"><B>6.  DISCLAIMER OF LIABILITY</B></FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2">EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES </FONT><FONT SIZE="2">(INCLUDING WITHOUT LIMITATION LOST PROFITS),</FONT><FONT SIZE="2"> HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"><B>7.  GENERAL</B></FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2">If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.</FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">If Recipient institutes patent litigation against a Contributor with respect to a patent applicable to software (including a cross-claim or counterclaim in a lawsuit), then any patent licenses granted by that Contributor to such Recipient under this Agreement shall terminate as of the date such litigation is filed.  In addition, if Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. </FONT><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance.  If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable.  However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.  </FONT><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2">Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted  and may only be modified in the following manner. The Agreement Steward reserves the right to </FONT><FONT SIZE="2">publish new versions (including revisions) of this Agreement from time to </FONT><FONT SIZE="2">time. No one other than the Agreement Steward has the right to modify this Agreement. IBM is the initial Agreement Steward.   IBM may assign the responsibility to serve as the Agreement Steward to a suitable separate entity.  </FONT><FONT SIZE="2">Each new version of the Agreement will be given a distinguishing version number.  The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new </FONT><FONT SIZE="2">version.  </FONT><FONT SIZE="2">Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, </FONT><FONT SIZE="2">by implication, estoppel or otherwise</FONT><FONT SIZE="2">.</FONT><FONT SIZE="2">  All rights in the Program not expressly granted under this Agreement are reserved.</FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose.  Each party waives its rights to a jury trial in any resulting litigation.</FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"></FONT>
+
+</BODY>
+
+</HTML>
\ No newline at end of file
diff --git a/legacy-test/src/junit/framework/Assert.java b/legacy-test/src/junit/framework/Assert.java
new file mode 100644
index 0000000..3dcc23d
--- /dev/null
+++ b/legacy-test/src/junit/framework/Assert.java
@@ -0,0 +1,296 @@
+package junit.framework;
+
+/**
+ * A set of assert methods.  Messages are only displayed when an assert fails.
+ */
+
+public class Assert {
+	/**
+	 * Protect constructor since it is a static only class
+	 */
+	protected Assert() {
+	}
+
+	/**
+	 * Asserts that a condition is true. If it isn't it throws
+	 * an AssertionFailedError with the given message.
+	 */
+	static public void assertTrue(String message, boolean condition) {
+		if (!condition)
+			fail(message);
+	}
+	/**
+	 * Asserts that a condition is true. If it isn't it throws
+	 * an AssertionFailedError.
+	 */
+	static public void assertTrue(boolean condition) {
+		assertTrue(null, condition);
+	}
+	/**
+	 * Asserts that a condition is false. If it isn't it throws
+	 * an AssertionFailedError with the given message.
+	 */
+	static public void assertFalse(String message, boolean condition) {
+		assertTrue(message, !condition);
+	}
+	/**
+	 * Asserts that a condition is false. If it isn't it throws
+	 * an AssertionFailedError.
+	 */
+	static public void assertFalse(boolean condition) {
+		assertFalse(null, condition);
+	}
+	/**
+	 * Fails a test with the given message.
+	 */
+	static public void fail(String message) {
+		if (message == null) {
+			throw new AssertionFailedError();
+		}
+		throw new AssertionFailedError(message);
+	}
+	/**
+	 * Fails a test with no message.
+	 */
+	static public void fail() {
+		fail(null);
+	}
+	/**
+	 * Asserts that two objects are equal. If they are not
+	 * an AssertionFailedError is thrown with the given message.
+	 */
+	static public void assertEquals(String message, Object expected, Object actual) {
+		if (expected == null && actual == null)
+			return;
+		if (expected != null && expected.equals(actual))
+			return;
+		failNotEquals(message, expected, actual);
+	}
+	/**
+	 * Asserts that two objects are equal. If they are not
+	 * an AssertionFailedError is thrown.
+	 */
+	static public void assertEquals(Object expected, Object actual) {
+	    assertEquals(null, expected, actual);
+	}
+	/**
+	 * Asserts that two Strings are equal. 
+	 */
+	static public void assertEquals(String message, String expected, String actual) {
+		if (expected == null && actual == null)
+			return;
+		if (expected != null && expected.equals(actual))
+			return;
+		String cleanMessage= message == null ? "" : message;
+		throw new ComparisonFailure(cleanMessage, expected, actual);
+	}
+	/**
+	 * Asserts that two Strings are equal. 
+	 */
+	static public void assertEquals(String expected, String actual) {
+	    assertEquals(null, expected, actual);
+	}
+	/**
+	 * Asserts that two doubles are equal concerning a delta.  If they are not
+	 * an AssertionFailedError is thrown with the given message.  If the expected
+	 * value is infinity then the delta value is ignored.
+	 */
+	static public void assertEquals(String message, double expected, double actual, double delta) {
+		if (Double.compare(expected, actual) == 0)
+			return;
+		if (!(Math.abs(expected-actual) <= delta))
+			failNotEquals(message, new Double(expected), new Double(actual));
+	}
+	/**
+	 * Asserts that two doubles are equal concerning a delta. If the expected
+	 * value is infinity then the delta value is ignored.
+	 */
+	static public void assertEquals(double expected, double actual, double delta) {
+	    assertEquals(null, expected, actual, delta);
+	}
+	/**
+	 * Asserts that two floats are equal concerning a positive delta. If they
+	 * are not an AssertionFailedError is thrown with the given message. If the
+	 * expected value is infinity then the delta value is ignored.
+	 */
+	static public void assertEquals(String message, float expected, float actual, float delta) {
+		if (Float.compare(expected, actual) == 0)
+			return;
+		if (!(Math.abs(expected - actual) <= delta))
+				failNotEquals(message, new Float(expected), new Float(actual));
+	}
+	/**
+	 * Asserts that two floats are equal concerning a delta. If the expected
+	 * value is infinity then the delta value is ignored.
+	 */
+	static public void assertEquals(float expected, float actual, float delta) {
+		assertEquals(null, expected, actual, delta);
+	}
+	/**
+	 * Asserts that two longs are equal. If they are not
+	 * an AssertionFailedError is thrown with the given message.
+	 */
+	static public void assertEquals(String message, long expected, long actual) {
+	    assertEquals(message, new Long(expected), new Long(actual));
+	}
+	/**
+	 * Asserts that two longs are equal.
+	 */
+	static public void assertEquals(long expected, long actual) {
+	    assertEquals(null, expected, actual);
+	}
+	/**
+	 * Asserts that two booleans are equal. If they are not
+	 * an AssertionFailedError is thrown with the given message.
+	 */
+	static public void assertEquals(String message, boolean expected, boolean actual) {
+    		assertEquals(message, Boolean.valueOf(expected), Boolean.valueOf(actual));
+  	}
+	/**
+	 * Asserts that two booleans are equal.
+ 	 */
+	static public void assertEquals(boolean expected, boolean actual) {
+		assertEquals(null, expected, actual);
+	}
+	/**
+	 * Asserts that two bytes are equal. If they are not
+	 * an AssertionFailedError is thrown with the given message.
+	 */
+  	static public void assertEquals(String message, byte expected, byte actual) {
+		assertEquals(message, new Byte(expected), new Byte(actual));
+	}
+	/**
+   	 * Asserts that two bytes are equal.
+	 */
+	static public void assertEquals(byte expected, byte actual) {
+		assertEquals(null, expected, actual);
+	}
+	/**
+	 * Asserts that two chars are equal. If they are not
+	 * an AssertionFailedError is thrown with the given message.
+	 */
+  	static public void assertEquals(String message, char expected, char actual) {
+    		assertEquals(message, new Character(expected), new Character(actual));
+  	}
+	/**
+	 * Asserts that two chars are equal.
+	 */
+  	static public void assertEquals(char expected, char actual) {
+		assertEquals(null, expected, actual);
+	}
+	/**
+	 * Asserts that two shorts are equal. If they are not
+	 * an AssertionFailedError is thrown with the given message.
+	 */
+	static public void assertEquals(String message, short expected, short actual) {
+    		assertEquals(message, new Short(expected), new Short(actual));
+	}
+  	/**
+	 * Asserts that two shorts are equal.
+	 */
+	static public void assertEquals(short expected, short actual) {
+		assertEquals(null, expected, actual);
+	}
+	/**
+	 * Asserts that two ints are equal. If they are not
+	 * an AssertionFailedError is thrown with the given message.
+	 */
+  	static public void assertEquals(String message, int expected, int actual) {
+		assertEquals(message, new Integer(expected), new Integer(actual));
+  	}
+  	/**
+   	 * Asserts that two ints are equal.
+	 */
+  	static public void assertEquals(int expected, int actual) {
+  		assertEquals(null, expected, actual);
+	}
+	/**
+	 * Asserts that an object isn't null.
+	 */
+	static public void assertNotNull(Object object) {
+		assertNotNull(null, object);
+	}
+	/**
+	 * Asserts that an object isn't null. If it is
+	 * an AssertionFailedError is thrown with the given message.
+	 */
+	static public void assertNotNull(String message, Object object) {
+		assertTrue(message, object != null);
+	}
+	/**
+	 * Asserts that an object is null. If it isn't an {@link AssertionError} is
+	 * thrown.
+	 * Message contains: Expected: <null> but was: object
+	 * 
+	 * @param object
+	 *            Object to check or <code>null</code>
+	 */
+	static public void assertNull(Object object) {
+		String message = "Expected: <null> but was: " + String.valueOf(object);
+		assertNull(message, object);
+	}
+	/**
+	 * Asserts that an object is null.  If it is not
+	 * an AssertionFailedError is thrown with the given message.
+	 */
+	static public void assertNull(String message, Object object) {
+		assertTrue(message, object == null);
+	}
+	/**
+	 * Asserts that two objects refer to the same object. If they are not
+	 * an AssertionFailedError is thrown with the given message.
+	 */
+	static public void assertSame(String message, Object expected, Object actual) {
+		if (expected == actual)
+			return;
+		failNotSame(message, expected, actual);
+	}
+	/**
+	 * Asserts that two objects refer to the same object. If they are not
+	 * the same an AssertionFailedError is thrown.
+	 */
+	static public void assertSame(Object expected, Object actual) {
+	    assertSame(null, expected, actual);
+	}
+	/**
+	 * Asserts that two objects do not refer to the same object. If they do
+	 * refer to the same object an AssertionFailedError is thrown with the
+	 * given message.
+	 */
+	static public void assertNotSame(String message, Object expected, Object actual) {
+		if (expected == actual)
+			failSame(message);
+	}
+	/**
+	 * Asserts that two objects do not refer to the same object. If they do
+	 * refer to the same object an AssertionFailedError is thrown.
+	 */
+	static public void assertNotSame(Object expected, Object actual) {
+		assertNotSame(null, expected, actual);
+	}
+
+	static public void failSame(String message) {
+		String formatted= "";
+ 		if (message != null)
+ 			formatted= message+" ";
+ 		fail(formatted+"expected not same");
+	}
+
+	static public void failNotSame(String message, Object expected, Object actual) {
+		String formatted= "";
+		if (message != null)
+			formatted= message+" ";
+		fail(formatted+"expected same:<"+expected+"> was not:<"+actual+">");
+	}
+
+	static public void failNotEquals(String message, Object expected, Object actual) {
+		fail(format(message, expected, actual));
+	}
+
+	public static String format(String message, Object expected, Object actual) {
+		String formatted= "";
+		if (message != null && message.length() > 0)
+			formatted= message+" ";
+		return formatted+"expected:<"+expected+"> but was:<"+actual+">";
+	}
+}
diff --git a/legacy-test/src/junit/framework/AssertionFailedError.java b/legacy-test/src/junit/framework/AssertionFailedError.java
new file mode 100644
index 0000000..0d7802c
--- /dev/null
+++ b/legacy-test/src/junit/framework/AssertionFailedError.java
@@ -0,0 +1,20 @@
+package junit.framework;
+
+/**
+ * Thrown when an assertion failed.
+ */
+public class AssertionFailedError extends AssertionError {
+
+	private static final long serialVersionUID= 1L;
+
+	public AssertionFailedError() {
+	}
+
+	public AssertionFailedError(String message) {
+		super(defaultString(message));
+	}
+
+	private static String defaultString(String message) {
+		return message == null ? "" : message;
+	}
+}
\ No newline at end of file
diff --git a/legacy-test/src/junit/framework/ComparisonCompactor.java b/legacy-test/src/junit/framework/ComparisonCompactor.java
new file mode 100644
index 0000000..e540f03
--- /dev/null
+++ b/legacy-test/src/junit/framework/ComparisonCompactor.java
@@ -0,0 +1,87 @@
+package junit.framework;
+
+// android-changed add @hide
+/**
+ * @hide not needed for public API
+ */
+public class ComparisonCompactor {
+
+	private static final String ELLIPSIS= "...";
+	private static final String DELTA_END= "]";
+	private static final String DELTA_START= "[";
+	
+	private int fContextLength;
+	private String fExpected;
+	private String fActual;
+	private int fPrefix;
+	private int fSuffix;
+
+	public ComparisonCompactor(int contextLength, String expected, String actual) {
+		fContextLength= contextLength;
+		fExpected= expected;
+		fActual= actual;
+	}
+
+	public String compact(String message) {
+		if (fExpected == null || fActual == null || areStringsEqual()) {
+			// android-changed use local method instead of Assert.format, since
+			// the later is not part of Android API till API 16
+			return format(message, fExpected, fActual);
+		}
+		findCommonPrefix();
+		findCommonSuffix();
+		String expected= compactString(fExpected);
+		String actual= compactString(fActual);
+		// android-changed use local format method
+		return format(message, expected, actual);
+	}
+
+	private String compactString(String source) {
+		String result= DELTA_START + source.substring(fPrefix, source.length() - fSuffix + 1) + DELTA_END;
+		if (fPrefix > 0)
+			result= computeCommonPrefix() + result;
+		if (fSuffix > 0)
+			result= result + computeCommonSuffix();
+		return result;
+	}
+
+	private void findCommonPrefix() {
+		fPrefix= 0;
+		int end= Math.min(fExpected.length(), fActual.length());
+		for (; fPrefix < end; fPrefix++) {
+			if (fExpected.charAt(fPrefix) != fActual.charAt(fPrefix))
+				break;
+		}
+	}
+
+	private void findCommonSuffix() {
+		int expectedSuffix= fExpected.length() - 1;
+		int actualSuffix= fActual.length() - 1;
+		for (; actualSuffix >= fPrefix && expectedSuffix >= fPrefix; actualSuffix--, expectedSuffix--) {
+			if (fExpected.charAt(expectedSuffix) != fActual.charAt(actualSuffix))
+				break;
+		}
+		fSuffix=  fExpected.length() - expectedSuffix;
+	}
+
+	private String computeCommonPrefix() {
+		return (fPrefix > fContextLength ? ELLIPSIS : "") + fExpected.substring(Math.max(0, fPrefix - fContextLength), fPrefix);
+	}
+
+	private String computeCommonSuffix() {
+		int end= Math.min(fExpected.length() - fSuffix + 1 + fContextLength, fExpected.length());
+		return fExpected.substring(fExpected.length() - fSuffix + 1, end) + (fExpected.length() - fSuffix + 1 < fExpected.length() - fContextLength ? ELLIPSIS : "");
+	}
+
+	private boolean areStringsEqual() {
+		return fExpected.equals(fActual);
+	}
+
+	// android-changed copy of Assert.format for reasons described above
+	private static String format(String message, Object expected, Object actual) {
+        	String formatted= "";
+        	if (message != null && message.length() > 0)
+            		formatted= message+" ";
+        	return formatted+"expected:<"+expected+"> but was:<"+actual+">";
+	}
+}
diff --git a/legacy-test/src/junit/framework/ComparisonFailure.java b/legacy-test/src/junit/framework/ComparisonFailure.java
new file mode 100644
index 0000000..5077993
--- /dev/null
+++ b/legacy-test/src/junit/framework/ComparisonFailure.java
@@ -0,0 +1,52 @@
+package junit.framework;
+
+/**
+ * Thrown when an assert equals for Strings failed.
+ * 
+ * Inspired by a patch from Alex Chaffee mailto:alex@purpletech.com
+ */
+public class ComparisonFailure extends AssertionFailedError {
+	private static final int MAX_CONTEXT_LENGTH= 20;
+	private static final long serialVersionUID= 1L;
+	
+	private String fExpected;
+	private String fActual;
+
+	/**
+	 * Constructs a comparison failure.
+	 * @param message the identifying message or null
+	 * @param expected the expected string value
+	 * @param actual the actual string value
+	 */
+	public ComparisonFailure (String message, String expected, String actual) {
+		super (message);
+		fExpected= expected;
+		fActual= actual;
+	}
+	
+	/**
+	 * Returns "..." in place of common prefix and "..." in
+	 * place of common suffix between expected and actual.
+	 * 
+	 * @see Throwable#getMessage()
+	 */
+	@Override
+	public String getMessage() {
+		return new ComparisonCompactor(MAX_CONTEXT_LENGTH, fExpected, fActual).compact(super.getMessage());
+	}
+	
+	/**
+	 * Gets the actual string value
+	 * @return the actual string value
+	 */
+	public String getActual() {
+		return fActual;
+	}
+	/**
+	 * Gets the expected string value
+	 * @return the expected string value
+	 */
+	public String getExpected() {
+		return fExpected;
+	}
+}
\ No newline at end of file
diff --git a/legacy-test/src/junit/framework/Protectable.java b/legacy-test/src/junit/framework/Protectable.java
new file mode 100644
index 0000000..e143237
--- /dev/null
+++ b/legacy-test/src/junit/framework/Protectable.java
@@ -0,0 +1,14 @@
+package junit.framework;
+
+/**
+ * A <em>Protectable</em> can be run and can throw a Throwable.
+ *
+ * @see TestResult
+ */
+public interface Protectable {
+
+	/**
+	 * Run the the following method protected.
+	 */
+	public abstract void protect() throws Throwable;
+}
\ No newline at end of file
diff --git a/legacy-test/src/junit/framework/Test.java b/legacy-test/src/junit/framework/Test.java
new file mode 100644
index 0000000..a016ee8
--- /dev/null
+++ b/legacy-test/src/junit/framework/Test.java
@@ -0,0 +1,17 @@
+package junit.framework;
+
+/**
+ * A <em>Test</em> can be run and collect its results.
+ *
+ * @see TestResult
+ */
+public interface Test {
+	/**
+	 * Counts the number of test cases that will be run by this test.
+	 */
+	public abstract int countTestCases();
+	/**
+	 * Runs a test and collects its result in a TestResult instance.
+	 */
+	public abstract void run(TestResult result);
+}
\ No newline at end of file
diff --git a/legacy-test/src/junit/framework/TestCase.java b/legacy-test/src/junit/framework/TestCase.java
new file mode 100644
index 0000000..b047ec9
--- /dev/null
+++ b/legacy-test/src/junit/framework/TestCase.java
@@ -0,0 +1,212 @@
+package junit.framework;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+/**
+ * A test case defines the fixture to run multiple tests. To define a test case<br/>
+ * <ol>
+ *   <li>implement a subclass of <code>TestCase</code></li>
+ *   <li>define instance variables that store the state of the fixture</li>
+ *   <li>initialize the fixture state by overriding {@link #setUp()}</li>
+ *   <li>clean-up after a test by overriding {@link #tearDown()}.</li>
+ * </ol>
+ * Each test runs in its own fixture so there
+ * can be no side effects among test runs.
+ * Here is an example:
+ * <pre>
+ * public class MathTest extends TestCase {
+ *    protected double fValue1;
+ *    protected double fValue2;
+ *
+ *    protected void setUp() {
+ *       fValue1= 2.0;
+ *       fValue2= 3.0;
+ *    }
+ * }
+ * </pre>
+ *
+ * For each test implement a method which interacts
+ * with the fixture. Verify the expected results with assertions specified
+ * by calling {@link junit.framework.Assert#assertTrue(String, boolean)} with a boolean.
+ * <pre>
+ *    public void testAdd() {
+ *       double result= fValue1 + fValue2;
+ *       assertTrue(result == 5.0);
+ *    }
+ * </pre>
+ * 
+ * Once the methods are defined you can run them. The framework supports
+ * both a static type safe and more dynamic way to run a test.
+ * In the static way you override the runTest method and define the method to
+ * be invoked. A convenient way to do so is with an anonymous inner class.
+ * <pre>
+ * TestCase test= new MathTest("add") {
+ *    public void runTest() {
+ *       testAdd();
+ *    }
+ * };
+ * test.run();
+ * </pre>
+ * 
+ * The dynamic way uses reflection to implement {@link #runTest()}. It dynamically finds
+ * and invokes a method.
+ * In this case the name of the test case has to correspond to the test method
+ * to be run.
+ * <pre>
+ * TestCase test= new MathTest("testAdd");
+ * test.run();
+ * </pre>
+ * 
+ * The tests to be run can be collected into a TestSuite. JUnit provides
+ * different <i>test runners</i> which can run a test suite and collect the results.
+ * A test runner either expects a static method <code>suite</code> as the entry
+ * point to get a test to run or it will extract the suite automatically.
+ * <pre>
+ * public static Test suite() {
+ *    suite.addTest(new MathTest("testAdd"));
+ *    suite.addTest(new MathTest("testDivideByZero"));
+ *    return suite;
+ * }
+ * </pre>
+ * @see TestResult
+ * @see TestSuite
+ */
+public abstract class TestCase extends Assert implements Test {
+	/**
+	 * the name of the test case
+	 */
+	private String fName;
+
+	/**
+	 * No-arg constructor to enable serialization. This method
+	 * is not intended to be used by mere mortals without calling setName().
+	 */
+	public TestCase() {
+		fName= null;
+	}
+	/**
+	 * Constructs a test case with the given name.
+	 */
+	public TestCase(String name) {
+		fName= name;
+	}
+	/**
+	 * Counts the number of test cases executed by run(TestResult result).
+	 */
+	public int countTestCases() {
+		return 1;
+	}
+	/**
+	 * Creates a default TestResult object
+	 *
+	 * @see TestResult
+	 */
+	protected TestResult createResult() {
+	    return new TestResult();
+	}
+	/**
+	 * A convenience method to run this test, collecting the results with a
+	 * default TestResult object.
+	 *
+	 * @see TestResult
+	 */
+	public TestResult run() {
+		TestResult result= createResult();
+		run(result);
+		return result;
+	}
+	/**
+	 * Runs the test case and collects the results in TestResult.
+	 */
+	public void run(TestResult result) {
+		result.run(this);
+	}
+	/**
+	 * Runs the bare test sequence.
+	 * @throws Throwable if any exception is thrown
+	 */
+	public void runBare() throws Throwable {
+		Throwable exception= null;
+		setUp();
+		try {
+			runTest();
+		} catch (Throwable running) {
+			exception= running;
+		}
+		finally {
+			try {
+				tearDown();
+			} catch (Throwable tearingDown) {
+				if (exception == null) exception= tearingDown;
+			}
+		}
+		if (exception != null) throw exception;
+	}
+	/**
+	 * Override to run the test and assert its state.
+	 * @throws Throwable if any exception is thrown
+	 */
+	protected void runTest() throws Throwable {
+		assertNotNull("TestCase.fName cannot be null", fName); // Some VMs crash when calling getMethod(null,null);
+		Method runMethod= null;
+		try {
+			// use getMethod to get all public inherited
+			// methods. getDeclaredMethods returns all
+			// methods of this class but excludes the
+			// inherited ones.
+			runMethod= getClass().getMethod(fName, (Class[])null);
+		} catch (NoSuchMethodException e) {
+			fail("Method \""+fName+"\" not found");
+		}
+		if (!Modifier.isPublic(runMethod.getModifiers())) {
+			fail("Method \""+fName+"\" should be public");
+		}
+
+		try {
+			runMethod.invoke(this);
+		}
+		catch (InvocationTargetException e) {
+			e.fillInStackTrace();
+			throw e.getTargetException();
+		}
+		catch (IllegalAccessException e) {
+			e.fillInStackTrace();
+			throw e;
+		}
+	}
+	/**
+	 * Sets up the fixture, for example, open a network connection.
+	 * This method is called before a test is executed.
+	 */
+	protected void setUp() throws Exception {
+	}
+	/**
+	 * Tears down the fixture, for example, close a network connection.
+	 * This method is called after a test is executed.
+	 */
+	protected void tearDown() throws Exception {
+	}
+	/**
+	 * Returns a string representation of the test case
+	 */
+	@Override
+	public String toString() {
+	    return getName() + "(" + getClass().getName() + ")";
+	}
+	/**
+	 * Gets the name of a TestCase
+	 * @return the name of the TestCase
+	 */
+	public String getName() {
+		return fName;
+	}
+	/**
+	 * Sets the name of a TestCase
+	 * @param name the name to set
+	 */
+	public void setName(String name) {
+		fName= name;
+	}
+}
diff --git a/legacy-test/src/junit/framework/TestFailure.java b/legacy-test/src/junit/framework/TestFailure.java
new file mode 100644
index 0000000..6662b1f
--- /dev/null
+++ b/legacy-test/src/junit/framework/TestFailure.java
@@ -0,0 +1,58 @@
+package junit.framework;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+
+/**
+ * A <code>TestFailure</code> collects a failed test together with
+ * the caught exception.
+ * @see TestResult
+ */
+public class TestFailure extends Object {
+	protected Test fFailedTest;
+	protected Throwable fThrownException;
+	
+
+	/**
+	 * Constructs a TestFailure with the given test and exception.
+	 */
+	public TestFailure(Test failedTest, Throwable thrownException) {
+		fFailedTest= failedTest;
+		fThrownException= thrownException;
+	}
+	/**
+	 * Gets the failed test.
+	 */
+	public Test failedTest() {
+	    return fFailedTest;
+	}
+	/**
+	 * Gets the thrown exception.
+	 */
+	public Throwable thrownException() {
+	    return fThrownException;
+	}
+	/**
+	 * Returns a short description of the failure.
+	 */
+	@Override
+	public String toString() {
+	    StringBuffer buffer= new StringBuffer();
+	    buffer.append(fFailedTest+": "+fThrownException.getMessage());
+	    return buffer.toString();
+	}
+	public String trace() {
+		StringWriter stringWriter= new StringWriter();
+		PrintWriter writer= new PrintWriter(stringWriter);
+		thrownException().printStackTrace(writer);
+		StringBuffer buffer= stringWriter.getBuffer();
+		return buffer.toString();
+	}
+	public String exceptionMessage() {
+		return thrownException().getMessage();
+	}
+	public boolean isFailure() {
+		return thrownException() instanceof AssertionFailedError;
+	}
+}
\ No newline at end of file
diff --git a/legacy-test/src/junit/framework/TestListener.java b/legacy-test/src/junit/framework/TestListener.java
new file mode 100644
index 0000000..9b69443
--- /dev/null
+++ b/legacy-test/src/junit/framework/TestListener.java
@@ -0,0 +1,23 @@
+package junit.framework;
+
+/**
+ * A Listener for test progress
+ */
+public interface TestListener {
+	/**
+ 	 * An error occurred.
+ 	 */
+	public void addError(Test test, Throwable t);
+	/**
+ 	 * A failure occurred.
+ 	 */
+ 	public void addFailure(Test test, AssertionFailedError t);  
+	/**
+	 * A test ended.
+	 */
+ 	public void endTest(Test test); 
+	/**
+	 * A test started.
+	 */
+	public void startTest(Test test);
+}
\ No newline at end of file
diff --git a/legacy-test/src/junit/framework/TestResult.java b/legacy-test/src/junit/framework/TestResult.java
new file mode 100644
index 0000000..3052e94
--- /dev/null
+++ b/legacy-test/src/junit/framework/TestResult.java
@@ -0,0 +1,174 @@
+package junit.framework;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Vector;
+
+/**
+ * A <code>TestResult</code> collects the results of executing
+ * a test case. It is an instance of the Collecting Parameter pattern.
+ * The test framework distinguishes between <i>failures</i> and <i>errors</i>.
+ * A failure is anticipated and checked for with assertions. Errors are
+ * unanticipated problems like an {@link ArrayIndexOutOfBoundsException}.
+ *
+ * @see Test
+ */
+public class TestResult extends Object {
+	// BEGIN android-changed changed types from List<> to Vector<> for API compatibility
+	protected Vector<TestFailure> fFailures;
+	protected Vector<TestFailure> fErrors;
+	protected Vector<TestListener> fListeners;
+	// END android-changed
+	protected int fRunTests;
+	private boolean fStop;
+	
+	public TestResult() {
+		// BEGIN android-changed to Vector
+		fFailures= new Vector<TestFailure>();
+		fErrors= new Vector<TestFailure>();
+		fListeners= new Vector<TestListener>();
+		// END android-changed
+		fRunTests= 0;
+		fStop= false;
+	}
+	/**
+	 * Adds an error to the list of errors. The passed in exception
+	 * caused the error.
+	 */
+	public synchronized void addError(Test test, Throwable t) {
+		fErrors.add(new TestFailure(test, t));
+		for (TestListener each : cloneListeners())
+			each.addError(test, t);
+	}
+	/**
+	 * Adds a failure to the list of failures. The passed in exception
+	 * caused the failure.
+	 */
+	public synchronized void addFailure(Test test, AssertionFailedError t) {
+		fFailures.add(new TestFailure(test, t));
+		for (TestListener each : cloneListeners())
+			each.addFailure(test, t);
+	}
+	/**
+	 * Registers a TestListener
+	 */
+	public synchronized void addListener(TestListener listener) {
+		fListeners.add(listener);
+	}
+	/**
+	 * Unregisters a TestListener
+	 */
+	public synchronized void removeListener(TestListener listener) {
+		fListeners.remove(listener);
+	}
+	/**
+	 * Returns a copy of the listeners.
+	 */
+	private synchronized List<TestListener> cloneListeners() {
+		List<TestListener> result= new ArrayList<TestListener>();
+		result.addAll(fListeners);
+		return result;
+	}
+	/**
+	 * Informs the result that a test was completed.
+	 */
+	public void endTest(Test test) {
+		for (TestListener each : cloneListeners())
+			each.endTest(test);
+	}
+	/**
+	 * Gets the number of detected errors.
+	 */
+	public synchronized int errorCount() {
+		return fErrors.size();
+	}
+	/**
+	 * Returns an Enumeration for the errors
+	 */
+	public synchronized Enumeration<TestFailure> errors() {
+		return Collections.enumeration(fErrors);
+	}
+	
+
+	/**
+	 * Gets the number of detected failures.
+	 */
+	public synchronized int failureCount() {
+		return fFailures.size();
+	}
+	/**
+	 * Returns an Enumeration for the failures
+	 */
+	public synchronized Enumeration<TestFailure> failures() {
+		return Collections.enumeration(fFailures);
+	}
+	
+	/**
+	 * Runs a TestCase.
+	 */
+	protected void run(final TestCase test) {
+		startTest(test);
+		Protectable p= new Protectable() {
+			public void protect() throws Throwable {
+				test.runBare();
+			}
+		};
+		runProtected(test, p);
+
+		endTest(test);
+	}
+	/**
+	 * Gets the number of run tests.
+	 */
+	public synchronized int runCount() {
+		return fRunTests;
+	}
+	/**
+	 * Runs a TestCase.
+	 */
+	public void runProtected(final Test test, Protectable p) {
+		try {
+			p.protect();
+		} 
+		catch (AssertionFailedError e) {
+			addFailure(test, e);
+		}
+		catch (ThreadDeath e) { // don't catch ThreadDeath by accident
+			throw e;
+		}
+		catch (Throwable e) {
+			addError(test, e);
+		}
+	}
+	/**
+	 * Checks whether the test run should stop
+	 */
+	public synchronized boolean shouldStop() {
+		return fStop;
+	}
+	/**
+	 * Informs the result that a test will be started.
+	 */
+	public void startTest(Test test) {
+		final int count= test.countTestCases();
+		synchronized(this) {
+			fRunTests+= count;
+		}
+		for (TestListener each : cloneListeners())
+			each.startTest(test);
+	}
+	/**
+	 * Marks that the test run should stop.
+	 */
+	public synchronized void stop() {
+		fStop= true;
+	}
+	/**
+	 * Returns whether the entire test was successful or not.
+	 */
+	public synchronized boolean wasSuccessful() {
+		return failureCount() == 0 && errorCount() == 0;
+	}
+}
diff --git a/legacy-test/src/junit/framework/TestSuite.java b/legacy-test/src/junit/framework/TestSuite.java
new file mode 100644
index 0000000..336efd1
--- /dev/null
+++ b/legacy-test/src/junit/framework/TestSuite.java
@@ -0,0 +1,307 @@
+package junit.framework;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Vector;
+
+/**
+ * <p>A <code>TestSuite</code> is a <code>Composite</code> of Tests.
+ * It runs a collection of test cases. Here is an example using
+ * the dynamic test definition.
+ * <pre>
+ * TestSuite suite= new TestSuite();
+ * suite.addTest(new MathTest("testAdd"));
+ * suite.addTest(new MathTest("testDivideByZero"));
+ * </pre>
+ * </p>
+ * 
+ * <p>Alternatively, a TestSuite can extract the tests to be run automatically.
+ * To do so you pass the class of your TestCase class to the
+ * TestSuite constructor.
+ * <pre>
+ * TestSuite suite= new TestSuite(MathTest.class);
+ * </pre>
+ * </p>
+ * 
+ * <p>This constructor creates a suite with all the methods
+ * starting with "test" that take no arguments.</p>
+ * 
+ * <p>A final option is to do the same for a large array of test classes.
+ * <pre>
+ * Class[] testClasses = { MathTest.class, AnotherTest.class }
+ * TestSuite suite= new TestSuite(testClasses);
+ * </pre>
+ * </p>
+ *
+ * @see Test
+ */
+public class TestSuite implements Test {
+
+	/**
+	 * ...as the moon sets over the early morning Merlin, Oregon
+	 * mountains, our intrepid adventurers type...
+	 */
+	static public Test createTest(Class<?> theClass, String name) {
+		Constructor<?> constructor;
+		try {
+			constructor= getTestConstructor(theClass);
+		} catch (NoSuchMethodException e) {
+			return warning("Class "+theClass.getName()+" has no public constructor TestCase(String name) or TestCase()");
+		}
+		Object test;
+		try {
+			if (constructor.getParameterTypes().length == 0) {
+				test= constructor.newInstance(new Object[0]);
+				if (test instanceof TestCase)
+					((TestCase) test).setName(name);
+			} else {
+				test= constructor.newInstance(new Object[]{name});
+			}
+		} catch (InstantiationException e) {
+			return(warning("Cannot instantiate test case: "+name+" ("+exceptionToString(e)+")"));
+		} catch (InvocationTargetException e) {
+			return(warning("Exception in constructor: "+name+" ("+exceptionToString(e.getTargetException())+")"));
+		} catch (IllegalAccessException e) {
+			return(warning("Cannot access test case: "+name+" ("+exceptionToString(e)+")"));
+		}
+		return (Test) test;
+	}
+	
+	/**
+	 * Gets a constructor which takes a single String as
+	 * its argument or a no arg constructor.
+	 */
+	public static Constructor<?> getTestConstructor(Class<?> theClass) throws NoSuchMethodException {
+		try {
+			return theClass.getConstructor(String.class);	
+		} catch (NoSuchMethodException e) {
+			// fall through
+		}
+		return theClass.getConstructor(new Class[0]);
+	}
+
+	/**
+	 * Returns a test which will fail and log a warning message.
+	 */
+	public static Test warning(final String message) {
+		return new TestCase("warning") {
+			@Override
+			protected void runTest() {
+				fail(message);
+			}
+		};
+	}
+
+	/**
+	 * Converts the stack trace into a string
+	 */
+	private static String exceptionToString(Throwable t) {
+		StringWriter stringWriter= new StringWriter();
+		PrintWriter writer= new PrintWriter(stringWriter);
+		t.printStackTrace(writer);
+		return stringWriter.toString();
+	}
+	
+	private String fName;
+
+	private Vector<Test> fTests= new Vector<Test>(10); // Cannot convert this to List because it is used directly by some test runners
+
+    /**
+	 * Constructs an empty TestSuite.
+	 */
+	public TestSuite() {
+	}
+	
+	/**
+	 * Constructs a TestSuite from the given class. Adds all the methods
+	 * starting with "test" as test cases to the suite.
+	 * Parts of this method were written at 2337 meters in the Hueffihuette,
+	 * Kanton Uri
+	 */
+	public TestSuite(final Class<?> theClass) {
+		addTestsFromTestCase(theClass);
+	}
+
+	private void addTestsFromTestCase(final Class<?> theClass) {
+		fName= theClass.getName();
+		try {
+			getTestConstructor(theClass); // Avoid generating multiple error messages
+		} catch (NoSuchMethodException e) {
+			addTest(warning("Class "+theClass.getName()+" has no public constructor TestCase(String name) or TestCase()"));
+			return;
+		}
+
+		if (!Modifier.isPublic(theClass.getModifiers())) {
+			addTest(warning("Class "+theClass.getName()+" is not public"));
+			return;
+		}
+
+		Class<?> superClass= theClass;
+		List<String> names= new ArrayList<String>();
+		while (Test.class.isAssignableFrom(superClass)) {
+			for (Method each : superClass.getDeclaredMethods())
+				addTestMethod(each, names, theClass);
+			superClass= superClass.getSuperclass();
+		}
+		if (fTests.size() == 0)
+			addTest(warning("No tests found in "+theClass.getName()));
+	}
+	
+	/**
+	 * Constructs a TestSuite from the given class with the given name.
+	 * @see TestSuite#TestSuite(Class)
+	 */
+	public TestSuite(Class<? extends TestCase>  theClass, String name) {
+		this(theClass);
+		setName(name);
+	}
+	
+   	/**
+	 * Constructs an empty TestSuite.
+	 */
+	public TestSuite(String name) {
+		setName(name);
+	}
+	
+	/**
+	 * Constructs a TestSuite from the given array of classes.  
+	 * @param classes {@link TestCase}s
+	 */
+	public TestSuite (Class<?>... classes) {
+		for (Class<?> each : classes)
+			addTest(testCaseForClass(each));
+	}
+
+	private Test testCaseForClass(Class<?> each) {
+		if (TestCase.class.isAssignableFrom(each))
+			return new TestSuite(each.asSubclass(TestCase.class));
+		else
+			return warning(each.getCanonicalName() + " does not extend TestCase");
+	}
+	
+	/**
+	 * Constructs a TestSuite from the given array of classes with the given name.
+	 * @see TestSuite#TestSuite(Class[])
+	 */
+	public TestSuite(Class<? extends TestCase>[] classes, String name) {
+		this(classes);
+		setName(name);
+	}
+	
+	/**
+	 * Adds a test to the suite.
+	 */
+	public void addTest(Test test) {
+		fTests.add(test);
+	}
+
+	/**
+	 * Adds the tests from the given class to the suite
+	 */
+	public void addTestSuite(Class<? extends TestCase> testClass) {
+		addTest(new TestSuite(testClass));
+	}
+	
+	/**
+	 * Counts the number of test cases that will be run by this test.
+	 */
+	public int countTestCases() {
+		int count= 0;
+		for (Test each : fTests)
+			count+=  each.countTestCases();
+		return count;
+	}
+
+	/**
+	 * Returns the name of the suite. Not all
+	 * test suites have a name and this method
+	 * can return null.
+	 */
+	public String getName() {
+		return fName;
+	}
+	 
+	/**
+	 * Runs the tests and collects their result in a TestResult.
+	 */
+	public void run(TestResult result) {
+		for (Test each : fTests) {
+	  		if (result.shouldStop() )
+	  			break;
+			runTest(each, result);
+		}
+	}
+
+	public void runTest(Test test, TestResult result) {
+		test.run(result);
+	}
+	 
+	/**
+	 * Sets the name of the suite.
+	 * @param name the name to set
+	 */
+	public void setName(String name) {
+		fName= name;
+	}
+
+	/**
+	 * Returns the test at the given index
+	 */
+	public Test testAt(int index) {
+		return fTests.get(index);
+	}
+	
+	/**
+	 * Returns the number of tests in this suite
+	 */
+	public int testCount() {
+		return fTests.size();
+	}
+	
+	/**
+	 * Returns the tests as an enumeration
+	 */
+	public Enumeration<Test> tests() {
+		return fTests.elements();
+	}
+	
+	/**
+	 */
+	@Override
+	public String toString() {
+		if (getName() != null)
+			return getName();
+		return super.toString();
+	 }
+
+	private void addTestMethod(Method m, List<String> names, Class<?> theClass) {
+		String name= m.getName();
+		if (names.contains(name))
+			return;
+		if (! isPublicTestMethod(m)) {
+			if (isTestMethod(m))
+				addTest(warning("Test method isn't public: "+ m.getName() + "(" + theClass.getCanonicalName() + ")"));
+			return;
+		}
+		names.add(name);
+		addTest(createTest(theClass, name));
+	}
+
+	private boolean isPublicTestMethod(Method m) {
+		return isTestMethod(m) && Modifier.isPublic(m.getModifiers());
+	 }
+	 
+	private boolean isTestMethod(Method m) {
+		return 
+			m.getParameterTypes().length == 0 && 
+			m.getName().startsWith("test") && 
+			m.getReturnType().equals(Void.TYPE);
+	 }
+}
\ No newline at end of file
diff --git a/libs/androidfw/tests/Split_test.cpp b/libs/androidfw/tests/Split_test.cpp
index 1f207e2..2c242db 100644
--- a/libs/androidfw/tests/Split_test.cpp
+++ b/libs/androidfw/tests/Split_test.cpp
@@ -165,7 +165,7 @@
                                     &specFlags, NULL);
   EXPECT_GE(block, 0);
 
-  EXPECT_EQ(static_cast<uint32_t>(0), specFlags);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), specFlags);
 
   ASSERT_EQ(NO_ERROR, table.add(basic_de_fr_contents_.data(),
                                 basic_de_fr_contents_.size()));
@@ -173,9 +173,10 @@
   uint32_t frSpecFlags = 0;
   block = table.getResource(R::string::test1, &val, MAY_NOT_BE_BAG, 0,
                             &frSpecFlags, NULL);
-  EXPECT_GE(block, 0);
+  ASSERT_GE(block, 0);
 
-  EXPECT_EQ(ResTable_config::CONFIG_LOCALE, frSpecFlags);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_config::CONFIG_LOCALE | ResTable_typeSpec::SPEC_PUBLIC),
+            frSpecFlags);
 }
 
 TEST_F(SplitTest, SelectBestDensity) {
@@ -222,7 +223,7 @@
             table.add(feature_contents_.data(), feature_contents_.size()));
 
   block = table.getResource(R::string::test3, &val, MAY_NOT_BE_BAG);
-  EXPECT_GE(block, 0);
+  ASSERT_GE(block, 0);
 
   EXPECT_EQ(Res_value::TYPE_STRING, val.dataType);
 }
diff --git a/libs/androidfw/tests/data/basic/basic.apk b/libs/androidfw/tests/data/basic/basic.apk
index 2d71f5b..2c9771b 100644
--- a/libs/androidfw/tests/data/basic/basic.apk
+++ b/libs/androidfw/tests/data/basic/basic.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/basic_de_fr.apk b/libs/androidfw/tests/data/basic/basic_de_fr.apk
index 69a2f30..0481444 100644
--- a/libs/androidfw/tests/data/basic/basic_de_fr.apk
+++ b/libs/androidfw/tests/data/basic/basic_de_fr.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/basic_hdpi-v4.apk b/libs/androidfw/tests/data/basic/basic_hdpi-v4.apk
index 011808b..a8d06e7 100644
--- a/libs/androidfw/tests/data/basic/basic_hdpi-v4.apk
+++ b/libs/androidfw/tests/data/basic/basic_hdpi-v4.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/basic_xhdpi-v4.apk b/libs/androidfw/tests/data/basic/basic_xhdpi-v4.apk
index 6d4353c..d1dfb14 100644
--- a/libs/androidfw/tests/data/basic/basic_xhdpi-v4.apk
+++ b/libs/androidfw/tests/data/basic/basic_xhdpi-v4.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/basic_xxhdpi-v4.apk b/libs/androidfw/tests/data/basic/basic_xxhdpi-v4.apk
index e3bda88..dca6f2f 100644
--- a/libs/androidfw/tests/data/basic/basic_xxhdpi-v4.apk
+++ b/libs/androidfw/tests/data/basic/basic_xxhdpi-v4.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/build b/libs/androidfw/tests/data/basic/build
index 68b911a..af0fd87 100755
--- a/libs/androidfw/tests/data/basic/build
+++ b/libs/androidfw/tests/data/basic/build
@@ -17,6 +17,6 @@
 
 set -e
 
-PATH_TO_FRAMEWORK_RES=$(gettop)/prebuilts/sdk/current/android.jar
+PATH_TO_FRAMEWORK_RES=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/android.jar
 
 aapt package -M AndroidManifest.xml -S res -I $PATH_TO_FRAMEWORK_RES --split hdpi --split xhdpi --split xxhdpi --split fr,de -F basic.apk -f
diff --git a/libs/androidfw/tests/data/basic/res/values/values.xml b/libs/androidfw/tests/data/basic/res/values/values.xml
index 75e0435..11f6b8a 100644
--- a/libs/androidfw/tests/data/basic/res/values/values.xml
+++ b/libs/androidfw/tests/data/basic/res/values/values.xml
@@ -15,24 +15,40 @@
 -->
 
 <resources>
+    <public type="attr" name="attr1" id="0x7f010000" />
     <attr name="attr1" format="reference|integer" />
+
+    <public type="attr" name="attr2" id="0x7f010001" />
     <attr name="attr2" format="reference|integer" />
 
+    <public type="layout" name="main" id="0x7f020000" />
+
+    <public type="string" name="test1" id="0x7f030000" />
     <string name="test1">test1</string>
+
+    <public type="string" name="test2" id="0x7f030001" />
     <string name="test2">test2</string>
 
+    <public type="string" name="density" id="0x7f030002" />
+
+    <public type="integer" name="number1" id="0x7f040000" />
     <integer name="number1">200</integer>
+
+    <public type="integer" name="number2" id="0x7f040001" />
     <integer name="number2">@array/integerArray1</integer>
 
+    <public type="style" name="Theme1" id="0x7f050000" />
     <style name="Theme1">
         <item name="com.android.basic:attr1">100</item>
         <item name="com.android.basic:attr2">@integer/number1</item>
     </style>
 
+    <public type="style" name="Theme2" id="0x7f050001" />
     <style name="Theme2" parent="@com.android.basic:style/Theme1">
         <item name="com.android.basic:attr1">300</item>
     </style>
 
+    <public type="array" name="integerArray1" id="0x7f060000" />
     <integer-array name="integerArray1">
         <item>1</item>
         <item>2</item>
diff --git a/libs/androidfw/tests/data/feature/build b/libs/androidfw/tests/data/feature/build
index 3316e41..6ed3e41 100755
--- a/libs/androidfw/tests/data/feature/build
+++ b/libs/androidfw/tests/data/feature/build
@@ -17,4 +17,6 @@
 
 set -e
 
-aapt package -M AndroidManifest.xml -S res --feature-of ../basic/basic.apk -F feature.apk -f
+PATH_TO_FRAMEWORK_RES=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/android.jar
+
+aapt package -M AndroidManifest.xml -S res -I $PATH_TO_FRAMEWORK_RES --feature-of ../basic/basic.apk -F feature.apk -f
diff --git a/libs/androidfw/tests/data/feature/feature.apk b/libs/androidfw/tests/data/feature/feature.apk
index 1e65c27..04940fb 100644
--- a/libs/androidfw/tests/data/feature/feature.apk
+++ b/libs/androidfw/tests/data/feature/feature.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/feature/res/values/values.xml b/libs/androidfw/tests/data/feature/res/values/values.xml
index 343fd6c..59f7d93 100644
--- a/libs/androidfw/tests/data/feature/res/values/values.xml
+++ b/libs/androidfw/tests/data/feature/res/values/values.xml
@@ -15,8 +15,13 @@
 -->
 
 <resources>
+    <!-- Features are offset, so 7f020000 will become 7f080000 at runtime. -->
+    <public type="string" name="test3" id="0x7f020000" />
     <string name="test3">test3</string>
+
+    <public type="string" name="test4" id="0x7f020001" />
     <string name="test4">test4</string>
 
+    <public type="integer" name="number3" id="0x7f030000" />
     <integer name="number3">200</integer>
 </resources>
diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp
index 489039c..dbbf00d 100644
--- a/libs/hwui/CanvasState.cpp
+++ b/libs/hwui/CanvasState.cpp
@@ -225,7 +225,7 @@
     bool outlineIsRounded = MathUtils::isPositive(radius);
     if (!outlineIsRounded || currentTransform()->isSimple()) {
         // TODO: consider storing this rect separately, so that this can't be replaced with clip ops
-        clipRect(bounds.left, bounds.top, bounds.right, bounds.bottom, kIntersect_SkClipOp);
+        clipRect(bounds.left, bounds.top, bounds.right, bounds.bottom, SkClipOp::kIntersect);
     }
     if (outlineIsRounded) {
         setClippingRoundRect(allocator, bounds, radius, false);
diff --git a/libs/hwui/FloatColor.h b/libs/hwui/FloatColor.h
index 9df7338..d8afa35 100644
--- a/libs/hwui/FloatColor.h
+++ b/libs/hwui/FloatColor.h
@@ -38,13 +38,13 @@
     }
 
     // "color" is a gamma-encoded sRGB color
-    // After calling this method, the color is stored as a pre-multiplied linear color
-    // if linear blending is enabled.
-    void setSRGB(uint32_t color) {
+    // After calling this method, the color is stored as a linear color. The color
+    // is not pre-multiplied.
+    void setUnPreMultipliedSRGB(uint32_t color) {
         a = ((color >> 24) & 0xff) / 255.0f;
-        r = a * EOCF_sRGB(((color >> 16) & 0xff) / 255.0f);
-        g = a * EOCF_sRGB(((color >>  8) & 0xff) / 255.0f);
-        b = a * EOCF_sRGB(((color      ) & 0xff) / 255.0f);
+        r = EOCF_sRGB(((color >> 16) & 0xff) / 255.0f);
+        g = EOCF_sRGB(((color >>  8) & 0xff) / 255.0f);
+        b = EOCF_sRGB(((color      ) & 0xff) / 255.0f);
     }
 
     bool isNotBlack() {
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index 5b683e0..a53a55a 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -120,7 +120,7 @@
     mCanvasState.save(SaveFlags::MatrixClip);
     mCanvasState.translate(tx, ty);
     mCanvasState.clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom,
-            kIntersect_SkClipOp);
+            SkClipOp::kIntersect);
     deferNodePropsAndOps(renderNode);
     mCanvasState.restore();
 }
@@ -262,7 +262,7 @@
         Rect clipRect;
         properties.getClippingRectForFlags(clipFlags, &clipRect);
         mCanvasState.clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom,
-                kIntersect_SkClipOp);
+                SkClipOp::kIntersect);
     }
 
     if (properties.getRevealClip().willClip()) {
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index 0972ac1..1dad58f 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -188,26 +188,28 @@
 void GradientCache::mixBytes(const FloatColor& start, const FloatColor& end,
         float amount, uint8_t*& dst) const {
     float oppAmount = 1.0f - amount;
-    *dst++ = uint8_t(OECF_sRGB(start.r * oppAmount + end.r * amount) * 255.0f);
-    *dst++ = uint8_t(OECF_sRGB(start.g * oppAmount + end.g * amount) * 255.0f);
-    *dst++ = uint8_t(OECF_sRGB(start.b * oppAmount + end.b * amount) * 255.0f);
-    *dst++ = uint8_t(         (start.a * oppAmount + end.a * amount) * 255.0f);
+    float a = start.a * oppAmount + end.a * amount;
+    *dst++ = uint8_t(a * OECF_sRGB((start.r * oppAmount + end.r * amount)) * 255.0f);
+    *dst++ = uint8_t(a * OECF_sRGB((start.g * oppAmount + end.g * amount)) * 255.0f);
+    *dst++ = uint8_t(a * OECF_sRGB((start.b * oppAmount + end.b * amount)) * 255.0f);
+    *dst++ = uint8_t(a * 255.0f);
 }
 
 void GradientCache::mixFloats(const FloatColor& start, const FloatColor& end,
         float amount, uint8_t*& dst) const {
     float oppAmount = 1.0f - amount;
+    float a = start.a * oppAmount + end.a * amount;
     float* d = (float*) dst;
 #ifdef ANDROID_ENABLE_LINEAR_BLENDING
-    *d++ = start.r * oppAmount + end.r * amount;
-    *d++ = start.g * oppAmount + end.g * amount;
-    *d++ = start.b * oppAmount + end.b * amount;
+    *d++ = a * (start.r * oppAmount + end.r * amount);
+    *d++ = a * (start.g * oppAmount + end.g * amount);
+    *d++ = a * (start.b * oppAmount + end.b * amount);
 #else
-    *d++ = OECF_sRGB(start.r * oppAmount + end.r * amount);
-    *d++ = OECF_sRGB(start.g * oppAmount + end.g * amount);
-    *d++ = OECF_sRGB(start.b * oppAmount + end.b * amount);
+    *d++ = a * OECF_sRGB(start.r * oppAmount + end.r * amount);
+    *d++ = a * OECF_sRGB(start.g * oppAmount + end.g * amount);
+    *d++ = a * OECF_sRGB(start.b * oppAmount + end.b * amount);
 #endif
-    *d++ = start.a * oppAmount + end.a * amount;
+    *d++ = a;
     dst += 4 * sizeof(float);
 }
 
@@ -217,16 +219,19 @@
     uint8_t pixels[rowBytes * height];
 
     static ChannelMixer gMixers[] = {
-            &android::uirenderer::GradientCache::mixBytes,  // colors are stored gamma-encoded
-            &android::uirenderer::GradientCache::mixFloats, // colors are stored in linear
+            // colors are stored gamma-encoded
+            &android::uirenderer::GradientCache::mixBytes,
+            // colors are stored in linear (linear blending on)
+            // or gamma-encoded (linear blending off)
+            &android::uirenderer::GradientCache::mixFloats,
     };
     ChannelMixer mix = gMixers[mUseFloatTexture];
 
     FloatColor start;
-    start.setSRGB(colors[0]);
+    start.setUnPreMultipliedSRGB(colors[0]);
 
     FloatColor end;
-    end.setSRGB(colors[1]);
+    end.setUnPreMultipliedSRGB(colors[1]);
 
     int currentPos = 1;
     float startPos = positions[0];
@@ -241,7 +246,7 @@
 
             currentPos++;
 
-            end.setSRGB(colors[currentPos]);
+            end.setUnPreMultipliedSRGB(colors[currentPos]);
             distance = positions[currentPos] - startPos;
         }
 
diff --git a/libs/hwui/OpenGLReadback.cpp b/libs/hwui/OpenGLReadback.cpp
index 74a8395..938b6ef 100644
--- a/libs/hwui/OpenGLReadback.cpp
+++ b/libs/hwui/OpenGLReadback.cpp
@@ -108,6 +108,15 @@
     return copyGraphicBufferInto(graphicBuffer, transform, srcRect, bitmap);
 }
 
+static float sFlipVInit[16] = {
+    1, 0, 0, 0,
+    0, -1, 0, 0,
+    0, 0, 1, 0,
+    0, 1, 0, 1,
+};
+
+static const Matrix4 sFlipV(sFlipVInit);
+
 ////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -122,6 +131,13 @@
                 destWidth, destHeight, caches.maxTextureSize);
         return CopyResult::DestinationInvalid;
     }
+
+    // TODO: Add support for RGBA_F16 destinations
+    if (bitmap->colorType() == kRGBA_F16_SkColorType) {
+        ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported");
+        return CopyResult::DestinationInvalid;
+    }
+
     GLuint fbo = renderState.createFramebuffer();
     if (!fbo) {
         ALOGW("Could not obtain an FBO");
@@ -183,11 +199,15 @@
 
         Matrix4 croppedTexTransform(texTransform);
         if (!srcRect.isEmpty()) {
-            croppedTexTransform.loadTranslate(srcRect.left / sourceTexture.width(),
+            // We flipV to convert to 0,0 top-left for the srcRect
+            // coordinates then flip back to 0,0 bottom-left for
+            // GLES coordinates.
+            croppedTexTransform.multiply(sFlipV);
+            croppedTexTransform.translate(srcRect.left / sourceTexture.width(),
                     srcRect.top / sourceTexture.height(), 0);
             croppedTexTransform.scale(srcRect.getWidth() / sourceTexture.width(),
                     srcRect.getHeight() / sourceTexture.height(), 1);
-            croppedTexTransform.multiply(texTransform);
+            croppedTexTransform.multiply(sFlipV);
         }
         Glop glop;
         GlopBuilder(renderState, caches, &glop)
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
index 52c62cc..983c17e 100644
--- a/libs/hwui/PatchCache.cpp
+++ b/libs/hwui/PatchCache.cpp
@@ -36,8 +36,7 @@
         , mSize(0)
         , mCache(LruCache<PatchDescription, Patch*>::kUnlimitedCapacity)
         , mMeshBuffer(0)
-        , mFreeBlocks(nullptr)
-        , mGenerationId(0) {}
+        , mFreeBlocks(nullptr) {}
 
 PatchCache::~PatchCache() {
     clear();
@@ -158,7 +157,6 @@
         mMaxSize, nullptr, GL_DYNAMIC_DRAW);
     mSize = 0;
     mFreeBlocks = new BufferBlock(0, mMaxSize);
-    mGenerationId++;
 }
 
 /**
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
index 0624c35..aa746c7 100644
--- a/libs/hwui/PatchCache.h
+++ b/libs/hwui/PatchCache.h
@@ -69,10 +69,6 @@
         return mMeshBuffer;
     }
 
-    uint32_t getGenerationId() const {
-        return mGenerationId;
-    }
-
     /**
      * Removes the entries associated with the specified 9-patch. This is meant
      * to be called from threads that are not the EGL context thread (GC thread
@@ -175,8 +171,6 @@
     // First available free block inside the mesh buffer
     BufferBlock* mFreeBlocks;
 
-    uint32_t mGenerationId;
-
     // Garbage tracking, required to handle GC events on the VM side
     Vector<Res_png_9patch*> mGarbage;
     mutable Mutex mLock;
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index 9c4cb09..e70982f 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -54,6 +54,7 @@
 #define PROGRAM_KEY_COLOR_MATRIX        0x20
 #define PROGRAM_KEY_COLOR_BLEND         0x40
 #define PROGRAM_KEY_BITMAP_NPOT         0x80
+#define PROGRAM_KEY_BITMAP_EXTERNAL    0x100
 
 #define PROGRAM_KEY_SWAP_SRC_DST      0x2000
 
@@ -133,6 +134,7 @@
 
     // Shaders
     bool hasBitmap;
+    bool isShaderBitmapExternal;
     bool useShaderBasedWrap;
 
     bool hasVertexAlpha;
@@ -180,6 +182,7 @@
         modulate = false;
 
         hasBitmap = false;
+        isShaderBitmapExternal = false;
         useShaderBasedWrap = false;
 
         hasGradient = false;
@@ -239,6 +242,9 @@
                 key |= getEnumForWrap(bitmapWrapS) << PROGRAM_BITMAP_WRAPS_SHIFT;
                 key |= getEnumForWrap(bitmapWrapT) << PROGRAM_BITMAP_WRAPT_SHIFT;
             }
+            if (isShaderBitmapExternal) {
+                key |= PROGRAM_KEY_BITMAP_EXTERNAL;
+            }
         }
         if (hasGradient) key |= PROGRAM_KEY_GRADIENT;
         key |= programid(gradientType) << PROGRAM_GRADIENT_TYPE_SHIFT;
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 0c2309f..7107679 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -145,6 +145,8 @@
 };
 const char* gFS_Uniforms_BitmapSampler =
         "uniform sampler2D bitmapSampler;\n";
+const char* gFS_Uniforms_BitmapExternalSampler =
+        "uniform samplerExternalOES bitmapSampler;\n";
 const char* gFS_Uniforms_ColorOp[3] = {
         // None
         "",
@@ -175,10 +177,11 @@
 const char* gFS_Gradient_Preamble[2] = {
         // Linear framebuffer
         "\nvec4 dither(const vec4 color) {\n"
-        "    return vec4(color.rgb + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0), color.a);"
+        "    return vec4(color.rgb + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0), color.a);\n"
         "}\n"
         "\nvec4 gammaMix(const vec4 a, const vec4 b, float v) {\n"
-        "    return pow(mix(a, b, v), vec4(vec3(1.0 / 2.2), 1.0));"
+        "    vec4 c = pow(mix(a, b, v), vec4(vec3(1.0 / 2.2), 1.0));\n"
+        "    return vec4(c.rgb * c.a, c.a);\n"
         "}\n",
         // sRGB framebuffer
         "\nvec4 dither(const vec4 color) {\n"
@@ -186,7 +189,8 @@
         "    return vec4(dithered * dithered, color.a);\n"
         "}\n"
         "\nvec4 gammaMix(const vec4 a, const vec4 b, float v) {\n"
-        "    return mix(a, b, v);"
+        "    vec4 c = mix(a, b, v);\n"
+        "    return vec4(c.rgb * c.a, c.a);\n"
         "}\n"
 };
 
@@ -576,7 +580,8 @@
     if (blendFramebuffer) {
         shader.append(gFS_Header_Extension_FramebufferFetch);
     }
-    if (description.hasExternalTexture) {
+    if (description.hasExternalTexture
+            || (description.hasBitmap && description.isShaderBitmapExternal)) {
         shader.append(gFS_Header_Extension_ExternalTexture);
     }
 
@@ -693,7 +698,11 @@
     }
 
     if (description.hasBitmap) {
-        shader.append(gFS_Uniforms_BitmapSampler);
+        if (description.isShaderBitmapExternal) {
+            shader.append(gFS_Uniforms_BitmapExternalSampler);
+        } else {
+            shader.append(gFS_Uniforms_BitmapSampler);
+        }
     }
     shader.append(gFS_Uniforms_ColorOp[static_cast<int>(description.colorOp)]);
 
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 8ab57c9d..8cae771 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -199,11 +199,11 @@
 int SkiaCanvas::saveLayer(float left, float top, float right, float bottom,
             const SkPaint* paint, SaveFlags::Flags flags) {
     const SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
-    const SkCanvas::SaveLayerRec rec(&bounds, paint, layerFlags(flags));
+    //always save matrix and clip to match the behaviour of Skia and HWUI pipelines and to ensure
+    //android state tracking behavior matches that of the Skia API (partial save is not supported)
+    const SkCanvas::SaveLayerRec rec(&bounds, paint, layerFlags(flags | SaveFlags::MatrixClip));
 
-    int count = mCanvas->saveLayer(rec);
-    recordPartialSave(flags);
-    return count;
+    return mCanvas->saveLayer(rec);
 }
 
 int SkiaCanvas::saveLayerAlpha(float left, float top, float right, float bottom,
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 34e6a06..fadb960 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -81,7 +81,7 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-// gradient shader matrix helpers
+// Gradient shader matrix helpers
 ///////////////////////////////////////////////////////////////////////////////
 
 static void toLinearUnitMatrix(const SkPoint pts[2], SkMatrix* matrix) {
@@ -161,7 +161,7 @@
     gradInfo.fColorOffsets = &colorOffsets[0];
     shader.asAGradient(&gradInfo);
 
-    if (CC_UNLIKELY(!isSimpleGradient(gradInfo))) {
+    if (CC_UNLIKELY(!description->isSimpleGradient)) {
         outData->gradientSampler = (*textureUnit)++;
 
 #ifndef SK_SCALAR_IS_FLOAT
@@ -174,8 +174,8 @@
         outData->gradientSampler = 0;
         outData->gradientTexture = nullptr;
 
-        outData->startColor.setSRGB(gradInfo.fColors[0]);
-        outData->endColor.setSRGB(gradInfo.fColors[1]);
+        outData->startColor.setUnPreMultipliedSRGB(gradInfo.fColors[0]);
+        outData->endColor.setUnPreMultipliedSRGB(gradInfo.fColors[1]);
     }
 
     return true;
@@ -218,6 +218,7 @@
     const float height = outData->bitmapTexture->height();
 
     description->hasBitmap = true;
+    description->isShaderBitmapExternal = hwuiBitmap->isHardware();
     // gralloc doesn't support non-clamp modes
     if (hwuiBitmap->isHardware() || (!caches.extensions().hasNPot()
             && (!isPowerOfTwo(width) || !isPowerOfTwo(height))
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 287e58a..4f92657 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -115,7 +115,7 @@
      * the specified operation. The specified rectangle is considered
      * already transformed.
      */
-    void clipTransformed(const Rect& r, SkClipOp op = kIntersect_SkClipOp);
+    void clipTransformed(const Rect& r, SkClipOp op = SkClipOp::kIntersect);
 
     /**
      * Modifies the current clip with the specified region and operation.
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
index 5b5b74e..705395e 100644
--- a/libs/hwui/Texture.cpp
+++ b/libs/hwui/Texture.cpp
@@ -225,6 +225,12 @@
         *outInternalFormat = GL_LUMINANCE;
         *outType = GL_UNSIGNED_BYTE;
         break;
+    case kRGBA_F16_SkColorType:
+        // This format is always linear
+        *outFormat = GL_RGBA;
+        *outInternalFormat = GL_RGBA16F;
+        *outType = GL_HALF_FLOAT;
+        break;
     default:
         LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", colorType);
         break;
diff --git a/libs/hwui/font/Font.h b/libs/hwui/font/Font.h
index 288f733..504dabb 100644
--- a/libs/hwui/font/Font.h
+++ b/libs/hwui/font/Font.h
@@ -22,14 +22,16 @@
 #include <utils/KeyedVector.h>
 
 #include <SkScalar.h>
-#include <SkGlyphCache.h>
 #include <SkPaint.h>
 #include <SkPathMeasure.h>
+#include <SkTypeface.h>
 
 #include "FontUtil.h"
 #include "../Rect.h"
 #include "../Matrix.h"
 
+class SkGlyphCache;
+
 namespace android {
 namespace uirenderer {
 
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 64ef866..a9058b1 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -106,6 +106,10 @@
         return PIXEL_FORMAT_RGBA_8888;
     case GL_RGBA:
         return PIXEL_FORMAT_RGBA_8888;
+    case GL_RGB:
+        return PIXEL_FORMAT_RGB_565;
+    case GL_RGBA16F:
+        return PIXEL_FORMAT_RGBA_FP16;
     default:
         LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", internalFormat);
         return PIXEL_FORMAT_UNKNOWN;
@@ -304,7 +308,8 @@
 
 sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer) {
     PixelFormat format = graphicBuffer->getPixelFormat();
-    if (!graphicBuffer.get() || format != PIXEL_FORMAT_RGBA_8888) {
+    if (!graphicBuffer.get() ||
+            (format != PIXEL_FORMAT_RGBA_8888 && format != PIXEL_FORMAT_RGBA_FP16)) {
         return nullptr;
     }
     SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index 14cc449..117395b 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -68,7 +68,7 @@
         if (pendingClip && !pendingClip->contains(rect)) {
             canvas->clipRect(*pendingClip);
         }
-        canvas->clipRRect(SkRRect::MakeRectXY(rect, radius, radius), kIntersect_SkClipOp, true);
+        canvas->clipRRect(SkRRect::MakeRectXY(rect, radius, radius), SkClipOp::kIntersect, true);
     } else {
         if (pendingClip) {
             (void)rect.intersect(*pendingClip);
@@ -263,7 +263,7 @@
     }
 
     if (properties.getRevealClip().willClip()) {
-        canvas->clipPath(*properties.getRevealClip().getPath(), kIntersect_SkClipOp, true);
+        canvas->clipPath(*properties.getRevealClip().getPath(), SkClipOp::kIntersect, true);
     } else if (properties.getOutline().willClip()) {
         clipOutline(properties.getOutline(), canvas, pendingClip);
         pendingClip = nullptr;
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 6606b02..430d6be 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -18,6 +18,7 @@
 
 #include "utils/TraceUtils.h"
 #include <SkImageEncoder.h>
+#include <SkImagePriv.h>
 #include <SkOSFile.h>
 #include <SkOverdrawCanvas.h>
 #include <SkOverdrawColorFilter.h>
@@ -99,7 +100,7 @@
             int saveCount = layerCanvas->save();
             SkASSERT(saveCount == 1);
 
-            layerCanvas->clipRect(layerDamage.toSkRect(), kReplace_SkClipOp);
+            layerCanvas->androidFramework_setDeviceClipRestriction(layerDamage.toSkIRect());
 
             auto savedLightCenter = mLightCenter;
             // map current light center into RenderNode's coordinate space
@@ -232,8 +233,8 @@
 void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
         const std::vector<sp<RenderNode>>& nodes, bool opaque, const Rect &contentDrawBounds,
         SkCanvas* canvas) {
-
-    canvas->clipRect(clip, kReplace_SkClipOp);
+    SkAutoCanvasRestore saver(canvas, true);
+    canvas->androidFramework_setDeviceClipRestriction(clip.roundOut());
 
     if (!opaque) {
         canvas->clear(SK_ColorTRANSPARENT);
@@ -241,7 +242,6 @@
 
     if (1 == nodes.size()) {
         if (!nodes[0]->nothingToDraw()) {
-            SkAutoCanvasRestore acr(canvas, true);
             RenderNodeDrawable root(nodes[0].get(), canvas);
             root.draw(canvas);
         }
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 95db258..dbe0296 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -21,6 +21,7 @@
 #include "LayerDrawable.h"
 #include "NinePatchUtils.h"
 #include "pipeline/skia/AnimatedDrawables.h"
+#include <SkImagePriv.h>
 
 namespace android {
 namespace uirenderer {
diff --git a/include/private/README b/libs/hwui/private/README
similarity index 100%
rename from include/private/README
rename to libs/hwui/private/README
diff --git a/include/private/hwui/DrawGlInfo.h b/libs/hwui/private/hwui/DrawGlInfo.h
similarity index 100%
rename from include/private/hwui/DrawGlInfo.h
rename to libs/hwui/private/hwui/DrawGlInfo.h
diff --git a/libs/hwui/tests/common/BitmapAllocationTestUtils.h b/libs/hwui/tests/common/BitmapAllocationTestUtils.h
index 6dadd3e3..4892179 100644
--- a/libs/hwui/tests/common/BitmapAllocationTestUtils.h
+++ b/libs/hwui/tests/common/BitmapAllocationTestUtils.h
@@ -39,7 +39,9 @@
     static sk_sp<Bitmap> allocateHardwareBitmap(int width, int height,
             SkColorType colorType, std::function<void(SkBitmap& bitmap)> setup) {
         SkBitmap skBitmap;
-        sk_sp<Bitmap> heapBitmap(TestUtils::createBitmap(width, height, &skBitmap));
+        SkImageInfo info = SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType);
+        skBitmap.setInfo(info);
+        sk_sp<Bitmap> heapBitmap(Bitmap::allocateHeapBitmap(&skBitmap, nullptr));
         setup(skBitmap);
         return Bitmap::allocateHardwareBitmap(skBitmap);
     }
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index 243e401..5f6bcb3 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -24,6 +24,8 @@
 #include <utils/Unicode.h>
 #include <SkClipStack.h>
 
+#include <SkGlyphCache.h>
+
 namespace android {
 namespace uirenderer {
 
diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
index 9b0b950..e03c9e8 100644
--- a/libs/hwui/tests/common/scenes/BitmapShaders.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
@@ -17,6 +17,7 @@
 #include "TestSceneBase.h"
 #include "utils/Color.h"
 #include "tests/common/BitmapAllocationTestUtils.h"
+#include <SkImagePriv.h>
 
 class BitmapShaders;
 
@@ -70,4 +71,4 @@
     void doFrame(int frameNr) override { }
 
     BitmapAllocationTestUtils::BitmapAllocator mAllocator;
-};
\ No newline at end of file
+};
diff --git a/libs/hwui/tests/common/scenes/ClippingAnimation.cpp b/libs/hwui/tests/common/scenes/ClippingAnimation.cpp
index 45443b0..f47e05a 100644
--- a/libs/hwui/tests/common/scenes/ClippingAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ClippingAnimation.cpp
@@ -34,11 +34,11 @@
                 [](RenderProperties& props, Canvas& canvas) {
             canvas.save(SaveFlags::MatrixClip);
             {
-                canvas.clipRect(0, 0, 200, 200, kIntersect_SkClipOp);
+                canvas.clipRect(0, 0, 200, 200, SkClipOp::kIntersect);
                 canvas.translate(100, 100);
                 canvas.rotate(45);
                 canvas.translate(-100, -100);
-                canvas.clipRect(0, 0, 200, 200, kIntersect_SkClipOp);
+                canvas.clipRect(0, 0, 200, 200, SkClipOp::kIntersect);
                 canvas.drawColor(Color::Blue_500, SkBlendMode::kSrcOver);
             }
             canvas.restore();
@@ -47,7 +47,7 @@
             {
                 SkPath clipCircle;
                 clipCircle.addCircle(100, 300, 100);
-                canvas.clipPath(&clipCircle, kIntersect_SkClipOp);
+                canvas.clipPath(&clipCircle, SkClipOp::kIntersect);
                 canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
             }
             canvas.restore();
diff --git a/libs/hwui/tests/common/scenes/HwBitmap565.cpp b/libs/hwui/tests/common/scenes/HwBitmap565.cpp
new file mode 100644
index 0000000..18fea3d
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/HwBitmap565.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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 "utils/Color.h"
+#include "tests/common/BitmapAllocationTestUtils.h"
+
+class HwBitmap565;
+
+static TestScene::Registrar _HwBitmap565(TestScene::Info{
+    "hwBitmap565",
+    "Draws composite shader with hardware bitmap",
+    TestScene::simpleCreateScene<HwBitmap565>
+});
+
+class HwBitmap565 : public TestScene {
+public:
+    sp<RenderNode> card;
+    void createContent(int width, int height, Canvas& canvas) override {
+        canvas.drawColor(Color::Grey_200, SkBlendMode::kSrcOver);
+
+        sk_sp<Bitmap> hardwareBitmap = BitmapAllocationTestUtils::allocateHardwareBitmap(200, 200,
+                kRGB_565_SkColorType, [](SkBitmap& skBitmap) {
+            skBitmap.eraseColor(Color::White);
+            SkCanvas skCanvas(skBitmap);
+            SkPaint skPaint;
+            skPaint.setColor(Color::Red_500);
+            skCanvas.drawRect(SkRect::MakeWH(100, 100), skPaint);
+            skPaint.setColor(Color::Blue_500);
+            skCanvas.drawRect(SkRect::MakeXYWH(100, 100, 100, 100), skPaint);
+        });
+        canvas.drawBitmap(*hardwareBitmap, 10.0f, 10.0f, nullptr);
+    }
+
+    void doFrame(int frameNr) override { }
+};
\ No newline at end of file
diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
new file mode 100644
index 0000000..83b01e9
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
@@ -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.
+ */
+
+#include "TestSceneBase.h"
+#include "utils/Color.h"
+
+#include <gui/IGraphicBufferAlloc.h>
+#include <gui/ISurfaceComposer.h>
+#include <private/gui/ComposerService.h>
+#include <binder/IServiceManager.h>
+#include <ui/PixelFormat.h>
+#include <SkGradientShader.h>
+#include <SkImagePriv.h>
+
+class HwBitmapInCompositeShader;
+
+static TestScene::Registrar _HwBitmapInCompositeShader(TestScene::Info{
+    "hwbitmapcompositeshader",
+    "Draws composite shader with hardware bitmap",
+    TestScene::simpleCreateScene<HwBitmapInCompositeShader>
+});
+
+class HwBitmapInCompositeShader : public TestScene {
+public:
+    sp<RenderNode> card;
+    void createContent(int width, int height, Canvas& canvas) override {
+        canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
+
+        status_t error;
+        sp<ISurfaceComposer> composer(ComposerService::getComposerService());
+        sp<IGraphicBufferAlloc> alloc(composer->createGraphicBufferAlloc());
+        uint32_t usage = GraphicBuffer::USAGE_HW_TEXTURE
+                | GraphicBuffer::USAGE_SW_READ_NEVER
+                | GRALLOC_USAGE_SW_WRITE_RARELY;
+        sp<GraphicBuffer> buffer = alloc->createGraphicBuffer(400, 200, PIXEL_FORMAT_RGBA_8888, 1,
+                usage, &error);
+
+        unsigned char* pixels = nullptr;
+        buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, ((void**)&pixels));
+        size_t size = bytesPerPixel(buffer->getPixelFormat()) * buffer->getStride()
+                * buffer->getHeight();
+        memset(pixels, 0, size);
+        for (int i = 0; i < 6000; i++) {
+            pixels[4000 + 4 * i + 0] = 255;
+            pixels[4000 + 4 * i + 1] = 255;
+            pixels[4000 + 4 * i + 2] = 0;
+            pixels[4000 + 4 * i + 3] = 255;
+        }
+        buffer->unlock();
+        sk_sp<Bitmap> hardwareBitmap(Bitmap::createFrom(buffer));
+        sk_sp<SkShader> hardwareShader(createBitmapShader(*hardwareBitmap));
+
+        SkPoint center;
+        center.set(50, 50);
+        SkColor colors[2];
+        colors[0] = Color::Black;
+        colors[1] = Color::White;
+        sk_sp<SkShader> gradientShader = SkGradientShader::MakeRadial(center, 50, colors, nullptr,
+                2, SkShader::TileMode::kRepeat_TileMode);
+
+        sk_sp<SkShader> compositeShader(
+                SkShader::MakeComposeShader(hardwareShader, gradientShader, SkBlendMode::kDstATop));
+
+        SkPaint paint;
+        paint.setShader(std::move(compositeShader));
+        canvas.drawRoundRect(0, 0, 400, 200, 10.0f, 10.0f, paint);
+    }
+
+    void doFrame(int frameNr) override { }
+
+    sk_sp<SkShader> createBitmapShader(Bitmap& bitmap) {
+        SkBitmap skBitmap;
+        bitmap.getSkBitmapForShaders(&skBitmap);
+        sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(skBitmap, kNever_SkCopyPixelsMode);
+        return image->makeShader(SkShader::TileMode::kClamp_TileMode,
+                SkShader::TileMode::kClamp_TileMode);
+    }
+};
\ No newline at end of file
diff --git a/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp b/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
index 8b2852b..7e8a7d9 100644
--- a/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
@@ -36,7 +36,7 @@
             // nested clipped saveLayers
             canvas.saveLayerAlpha(0, 0, 400, 400, 200, SaveFlags::ClipToLayer);
             canvas.drawColor(Color::Green_700, SkBlendMode::kSrcOver);
-            canvas.clipRect(50, 50, 350, 350, kIntersect_SkClipOp);
+            canvas.clipRect(50, 50, 350, 350, SkClipOp::kIntersect);
             canvas.saveLayerAlpha(100, 100, 300, 300, 128, SaveFlags::ClipToLayer);
             canvas.drawColor(Color::Blue_500, SkBlendMode::kSrcOver);
             canvas.restore();
diff --git a/libs/hwui/tests/common/scenes/ShapeAnimation.cpp b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
index d44c3d5..09e70eb 100644
--- a/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
@@ -82,7 +82,7 @@
                     int middleCount = canvas.save(SaveFlags::MatrixClip);
                     for (auto op : ops) {
                         int innerCount = canvas.save(SaveFlags::MatrixClip);
-                        canvas.clipRect(0, 0, cellSize, cellSize, kIntersect_SkClipOp);
+                        canvas.clipRect(0, 0, cellSize, cellSize, SkClipOp::kIntersect);
                         canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
                         op(canvas, cellSize, paint);
                         canvas.restoreToCount(innerCount);
diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
index 3ef0d1c..f166c5c 100644
--- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
+++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
@@ -177,7 +177,7 @@
         // Clip to padding
         // Can expect ~25% of views to have clip to padding with a non-null padding
         int clipRestoreCount = canvas->save(SaveFlags::MatrixClip);
-        canvas->clipRect(1, 1, 199, 199, kIntersect_SkClipOp);
+        canvas->clipRect(1, 1, 199, 199, SkClipOp::kIntersect);
 
         canvas->insertReorderBarrier(true);
 
diff --git a/libs/hwui/tests/scripts/prep_marlfish.sh b/libs/hwui/tests/scripts/prep_marlfish.sh
new file mode 100755
index 0000000..f3c14d5
--- /dev/null
+++ b/libs/hwui/tests/scripts/prep_marlfish.sh
@@ -0,0 +1,45 @@
+#marlfish is marlin & sailfish  (☞゚ヮ゚)☞
+
+cpubase=/sys/devices/system/cpu
+
+adb root
+adb wait-for-device
+adb shell stop thermal-engine
+adb shell stop perfd
+
+# silver cores
+#307200 384000 460800 537600 614400 691200 768000 844800 902400 979200
+#1056000 1132800 1209600 1286400 1363200 1440000 1516800 1593600
+# gold cores
+#307200 384000 460800 537600 614400 691200 748800 825600 902400 979200
+#1056000 1132800 1209600 1286400 1363200 1440000 1516800 1593600 1670400
+#1747200 1824000 1900800 1977600 2054400 2150400
+
+S=979200
+cpu=0
+# Changing governor and frequency in one core will be automatically applied
+# to other cores in the cluster
+while [ $((cpu < 3)) -eq 1 ]; do
+    adb shell "echo userspace > $cpubase/cpu2/cpufreq/scaling_governor"
+    echo "Setting cpu ${cpu} & $(($cpu + 1)) cluster to $S hz"
+    adb shell "echo $S > $cpubase/cpu${cpu}/cpufreq/scaling_max_freq"
+    adb shell "echo $S > $cpubase/cpu${cpu}/cpufreq/scaling_min_freq"
+    cpu=$(($cpu + 2))
+done
+
+echo "setting GPU bus and idle timer"
+adb shell "echo 0 > /sys/class/kgsl/kgsl-3d0/bus_split"
+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 3143 4173 5195 5859 7759 9887 11863 13763
+adb shell "echo 13763 > /sys/class/devfreq/soc:qcom,gpubw/min_freq" &> /dev/null
+
+#133000000 214000000 315000000 401800000 510000000 560000000 624000000
+echo "performance mode, 315 MHz"
+adb shell "echo performance > /sys/class/kgsl/kgsl-3d0/devfreq/governor"
+adb shell "echo 315000000 > /sys/class/kgsl/kgsl-3d0/devfreq/min_freq"
+adb shell "echo 315000000 > /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/stopruntime.sh b/libs/hwui/tests/scripts/stopruntime.sh
index 85a91db..0a79618 100755
--- a/libs/hwui/tests/scripts/stopruntime.sh
+++ b/libs/hwui/tests/scripts/stopruntime.sh
@@ -23,4 +23,5 @@
 done
 adb shell setprop debug.egl.traceGpuCompletion 1
 adb shell setprop debug.sf.nobootanimation 1
+# Daemonize command is available only in eng builds.
 adb shell daemonize surfaceflinger
diff --git a/libs/hwui/tests/unit/CanvasStateTests.cpp b/libs/hwui/tests/unit/CanvasStateTests.cpp
index 7555fd4..43974f6 100644
--- a/libs/hwui/tests/unit/CanvasStateTests.cpp
+++ b/libs/hwui/tests/unit/CanvasStateTests.cpp
@@ -68,13 +68,13 @@
     state.initializeSaveStack(200, 200,
             0, 0, 200, 200, Vector3());
 
-    state.clipRect(0, 0, 100, 100, kIntersect_SkClipOp);
+    state.clipRect(0, 0, 100, 100, SkClipOp::kIntersect);
     ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(100, 100));
 
-    state.clipRect(10, 10, 200, 200, kIntersect_SkClipOp);
+    state.clipRect(10, 10, 200, 200, SkClipOp::kIntersect);
     ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10, 100, 100));
 
-    state.clipRect(50, 50, 150, 150, kReplace_SkClipOp);
+    state.clipRect(50, 50, 150, 150, SkClipOp::kReplace);
     ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(50, 50, 150, 150));
 }
 
@@ -88,7 +88,7 @@
         // rotated clip causes complex clip
         state.rotate(10);
         EXPECT_TRUE(state.clipIsSimple());
-        state.clipRect(0, 0, 200, 200, kIntersect_SkClipOp);
+        state.clipRect(0, 0, 200, 200, SkClipOp::kIntersect);
         EXPECT_FALSE(state.clipIsSimple());
     }
     state.restore();
@@ -97,7 +97,7 @@
     {
         // subtracted clip causes complex clip
         EXPECT_TRUE(state.clipIsSimple());
-        state.clipRect(50, 50, 150, 150, kDifference_SkClipOp);
+        state.clipRect(50, 50, 150, 150, SkClipOp::kDifference);
         EXPECT_FALSE(state.clipIsSimple());
     }
     state.restore();
@@ -108,7 +108,7 @@
         SkPath path;
         path.addOval(SkRect::MakeWH(200, 200));
         EXPECT_TRUE(state.clipIsSimple());
-        state.clipPath(&path, kDifference_SkClipOp);
+        state.clipPath(&path, SkClipOp::kDifference);
         EXPECT_FALSE(state.clipIsSimple());
     }
     state.restore();
@@ -121,7 +121,7 @@
 
     state.save(SaveFlags::Clip);
     {
-        state.clipRect(0, 0, 10, 10, kIntersect_SkClipOp);
+        state.clipRect(0, 0, 10, 10, SkClipOp::kIntersect);
         ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10));
     }
     state.restore();
@@ -145,7 +145,7 @@
 
     state.save(SaveFlags::Matrix); // NOTE: clip not saved
     {
-        state.clipRect(0, 0, 10, 10, kIntersect_SkClipOp);
+        state.clipRect(0, 0, 10, 10, SkClipOp::kIntersect);
         ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10));
     }
     state.restore();
diff --git a/libs/hwui/tests/unit/FatalTestCanvas.h b/libs/hwui/tests/unit/FatalTestCanvas.h
index b4132b7..4831722 100644
--- a/libs/hwui/tests/unit/FatalTestCanvas.h
+++ b/libs/hwui/tests/unit/FatalTestCanvas.h
@@ -121,13 +121,13 @@
             const SkPaint*) {
         ADD_FAILURE() << "onDrawBitmapLattice not expected in this test";
     }
-    void onClipRRect(const SkRRect& rrect, ClipOp, ClipEdgeStyle) {
+    void onClipRRect(const SkRRect& rrect, SkClipOp, ClipEdgeStyle) {
         ADD_FAILURE() << "onClipRRect not expected in this test";
     }
-    void onClipPath(const SkPath& path, ClipOp, ClipEdgeStyle) {
+    void onClipPath(const SkPath& path, SkClipOp, ClipEdgeStyle) {
         ADD_FAILURE() << "onClipPath not expected in this test";
     }
-    void onClipRegion(const SkRegion& deviceRgn, ClipOp) {
+    void onClipRegion(const SkRegion& deviceRgn, SkClipOp) {
         ADD_FAILURE() << "onClipRegion not expected in this test";
     }
     void onDiscard() {
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index 12622ff..21394ae 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -174,7 +174,7 @@
     auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
             [](RenderProperties& props, RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
-        canvas.clipRect(200, 200, 400, 400, kIntersect_SkClipOp); // intersection should be empty
+        canvas.clipRect(200, 200, 400, 400, SkClipOp::kIntersect); // intersection should be empty
         canvas.drawRect(0, 0, 400, 400, SkPaint());
         canvas.restore();
     });
@@ -453,19 +453,19 @@
         sk_sp<Bitmap> bitmap(TestUtils::createBitmap(20, 20));
 
         // left side clipped (to inset left half)
-        canvas.clipRect(10, 0, 50, 100, kReplace_SkClipOp);
+        canvas.clipRect(10, 0, 50, 100, SkClipOp::kReplace);
         canvas.drawBitmap(*bitmap, 0, 40, nullptr);
 
         // top side clipped (to inset top half)
-        canvas.clipRect(0, 10, 100, 50, kReplace_SkClipOp);
+        canvas.clipRect(0, 10, 100, 50, SkClipOp::kReplace);
         canvas.drawBitmap(*bitmap, 40, 0, nullptr);
 
         // right side clipped (to inset right half)
-        canvas.clipRect(50, 0, 90, 100, kReplace_SkClipOp);
+        canvas.clipRect(50, 0, 90, 100, SkClipOp::kReplace);
         canvas.drawBitmap(*bitmap, 80, 40, nullptr);
 
         // bottom not clipped, just abutting (inset bottom half)
-        canvas.clipRect(0, 50, 100, 90, kReplace_SkClipOp);
+        canvas.clipRect(0, 50, 100, 90, SkClipOp::kReplace);
         canvas.drawBitmap(*bitmap, 40, 70, nullptr);
     });
 
@@ -488,7 +488,7 @@
         SkPath path;
         path.addCircle(200, 200, 200, SkPath::kCW_Direction);
         canvas.save(SaveFlags::MatrixClip);
-        canvas.clipPath(&path, kIntersect_SkClipOp);
+        canvas.clipPath(&path, SkClipOp::kIntersect);
         SkPaint paint;
         paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
         paint.setAntiAlias(true);
@@ -649,7 +649,7 @@
     auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
             [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
-        canvas.clipRect(50, 50, 150, 150, kIntersect_SkClipOp);
+        canvas.clipRect(50, 50, 150, 150, SkClipOp::kIntersect);
         canvas.drawLayer(layerUpdater.get());
         canvas.restore();
     });
@@ -973,7 +973,7 @@
         auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
                 [](RenderProperties& props, RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
-        canvas.clipRect(200, 200, 400, 400, kIntersect_SkClipOp);
+        canvas.clipRect(200, 200, 400, 400, SkClipOp::kIntersect);
         canvas.saveLayerAlpha(200, 200, 400, 400, 128, SaveFlags::ClipToLayer);
 
         // draw within save layer may still be recorded, but shouldn't be drawn
@@ -1781,7 +1781,7 @@
     auto child = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
             [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
         // Record time clip will be ignored by projectee
-        canvas.clipRect(100, 100, 300, 300, kIntersect_SkClipOp);
+        canvas.clipRect(100, 100, 300, 300, SkClipOp::kIntersect);
 
         canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
         canvas.drawRenderNode(projectingRipple.get());
@@ -1993,7 +1993,7 @@
             [](RenderProperties& props, RecordingCanvas& canvas) {
         // Apply a clip before the reorder barrier/shadow casting child is drawn.
         // This clip must be applied to the shadow cast by the child.
-        canvas.clipRect(25, 25, 75, 75, kIntersect_SkClipOp);
+        canvas.clipRect(25, 25, 75, 75, SkClipOp::kIntersect);
         canvas.insertReorderBarrier(true);
         canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
     });
@@ -2252,7 +2252,7 @@
     };
     auto node = TestUtils::createNode<RecordingCanvas>(20, 20, 30, 30,
             [](RenderProperties& props, RecordingCanvas& canvas) {
-        canvas.clipRect(0, -20, 10, 30, kReplace_SkClipOp);
+        canvas.clipRect(0, -20, 10, 30, SkClipOp::kReplace);
         canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
     });
 
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index 14fa5d6..4a73383 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -25,6 +25,7 @@
 #include <utils/Color.h>
 
 #include <SkGradientShader.h>
+#include <SkImagePriv.h>
 #include <SkShader.h>
 
 namespace android {
@@ -57,7 +58,7 @@
 TEST(RecordingCanvas, clipRect) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
-        canvas.clipRect(0, 0, 100, 100, kIntersect_SkClipOp);
+        canvas.clipRect(0, 0, 100, 100, SkClipOp::kIntersect);
         canvas.drawRect(0, 0, 50, 50, SkPaint());
         canvas.drawRect(50, 50, 100, 100, SkPaint());
         canvas.restore();
@@ -73,8 +74,8 @@
 TEST(RecordingCanvas, emptyClipRect) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
-        canvas.clipRect(0, 0, 100, 100, kIntersect_SkClipOp);
-        canvas.clipRect(100, 100, 200, 200, kIntersect_SkClipOp);
+        canvas.clipRect(0, 0, 100, 100, SkClipOp::kIntersect);
+        canvas.clipRect(100, 100, 200, 200, SkClipOp::kIntersect);
         canvas.drawRect(0, 0, 50, 50, SkPaint()); // rejected at record time
         canvas.restore();
     });
@@ -440,7 +441,7 @@
 TEST(RecordingCanvas, saveLayer_addClipFlag) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
-        canvas.clipRect(10, 20, 190, 180, kIntersect_SkClipOp);
+        canvas.clipRect(10, 20, 190, 180, SkClipOp::kIntersect);
         canvas.saveLayerAlpha(10, 20, 190, 180, 128, (SaveFlags::Flags)0); // unclipped
         canvas.drawRect(10, 20, 190, 180, SkPaint());
         canvas.restore();
@@ -459,7 +460,7 @@
 TEST(RecordingCanvas, saveLayer_viewportCrop) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         // shouldn't matter, since saveLayer will clip to its bounds
-        canvas.clipRect(-1000, -1000, 1000, 1000, kReplace_SkClipOp);
+        canvas.clipRect(-1000, -1000, 1000, 1000, SkClipOp::kReplace);
 
         canvas.saveLayerAlpha(100, 100, 300, 300, 128, SaveFlags::ClipToLayer);
         canvas.drawRect(0, 0, 400, 400, SkPaint());
@@ -549,7 +550,7 @@
         canvas.save(SaveFlags::MatrixClip);
         canvas.translate(0, -20); // avoid identity case
         // empty clip rect should force layer + contents to be rejected
-        canvas.clipRect(0, -20, 200, -20, kIntersect_SkClipOp);
+        canvas.clipRect(0, -20, 200, -20, SkClipOp::kIntersect);
         canvas.saveLayerAlpha(0, 0, 200, 200, 128, SaveFlags::ClipToLayer);
         canvas.drawRect(0, 0, 200, 200, SkPaint());
         canvas.restore();
@@ -568,7 +569,7 @@
     });
 
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [&child](RecordingCanvas& canvas) {
-        canvas.clipRect(0, 0, 0, 0, kIntersect_SkClipOp); // empty clip, reject node
+        canvas.clipRect(0, 0, 0, 0, SkClipOp::kIntersect); // empty clip, reject node
         canvas.drawRenderNode(child.get()); // shouldn't crash when rejecting node...
     });
     ASSERT_TRUE(dl->isEmpty());
@@ -621,7 +622,7 @@
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
         // since no explicit clip set on canvas, this should be the one observed on op:
-        canvas.clipRect(-100, -100, 300, 300, kIntersect_SkClipOp);
+        canvas.clipRect(-100, -100, 300, 300, SkClipOp::kIntersect);
 
         SkPaint paint;
         paint.setColor(SK_ColorWHITE);
@@ -637,7 +638,7 @@
 TEST(RecordingCanvas, replaceClipIntersectWithRoot) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
-        canvas.clipRect(-10, -10, 110, 110, kReplace_SkClipOp);
+        canvas.clipRect(-10, -10, 110, 110, SkClipOp::kReplace);
         canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
         canvas.restore();
     });
@@ -675,7 +676,7 @@
         canvas.drawRect(0, 0, 400, 400, SkPaint());
 
         // second chunk: no recorded clip, since inorder region
-        canvas.clipRect(0, 0, 200, 200, kIntersect_SkClipOp);
+        canvas.clipRect(0, 0, 200, 200, SkClipOp::kIntersect);
         canvas.insertReorderBarrier(false);
         canvas.drawRect(0, 0, 400, 400, SkPaint());
 
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index 4d4705c..0906cc8 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -168,6 +168,59 @@
 }
 
 namespace {
+static SkRect getRecorderClipBounds(const SkiaRecordingCanvas& recorder) {
+    SkRect clipBounds;
+    recorder.getClipBounds(&clipBounds);
+    return clipBounds;
+}
+
+static SkMatrix getRecorderMatrix(const SkiaRecordingCanvas& recorder) {
+    SkMatrix matrix;
+    recorder.getMatrix(&matrix);
+    return matrix;
+}
+}
+
+TEST(RenderNodeDrawable, saveLayerClipAndMatrixRestore)
+{
+    auto surface = SkSurface::MakeRasterN32Premul(400, 800);
+    SkCanvas& canvas = *surface->getCanvas();
+    canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
+    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE);
+
+    auto rootNode = TestUtils::createSkiaNode(0, 0, 400, 800,
+        [](RenderProperties& props, SkiaRecordingCanvas& recorder) {
+            SkPaint layerPaint;
+            ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder));
+            EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
+
+            //note we don't pass SaveFlags::MatrixClip, but matrix and clip will be saved
+            recorder.saveLayer(0, 0, 400, 400, &layerPaint, SaveFlags::ClipToLayer);
+            ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 400), getRecorderClipBounds(recorder));
+            EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
+
+            recorder.clipRect(50, 50, 350, 350, SkClipOp::kIntersect);
+            ASSERT_EQ(SkRect::MakeLTRB(50, 50, 350, 350), getRecorderClipBounds(recorder));
+
+            recorder.translate(300.0f, 400.0f);
+            EXPECT_EQ(SkMatrix::MakeTrans(300.0f, 400.0f), getRecorderMatrix(recorder));
+
+            recorder.restore();
+            ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder));
+            EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
+
+            SkPaint paint;
+            paint.setAntiAlias(true);
+            paint.setColor(SK_ColorGREEN);
+            recorder.drawRect(0.0f, 400.0f, 400.0f, 800.0f, paint);
+        });
+
+    RenderNodeDrawable drawable(rootNode.get(), &canvas, true);
+    canvas.drawDrawable(&drawable);
+    ASSERT_EQ(SK_ColorGREEN, TestUtils::getColor(surface, 200, 600));
+}
+
+namespace {
 class ContextFactory : public IContextFactory {
 public:
     virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) override {
@@ -455,7 +508,7 @@
     auto child = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
             [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
         // Record time clip will be ignored by projectee
-        canvas.clipRect(100, 100, 300, 300, kIntersect_SkClipOp);
+        canvas.clipRect(100, 100, 300, 300, SkClipOp::kIntersect);
 
         canvas.translate(-SCROLL_X, -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
         canvas.drawRenderNode(projectingRipple.get());
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 9b5fa30..f3a663e 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -201,13 +201,11 @@
 template <typename T>
 class DeferLayer : public SkSurface_Base {
 public:
-    DeferLayer(T *canvas)
-        : SkSurface_Base(canvas->imageInfo(), nullptr)
-        , mCanvas(canvas) {
+    DeferLayer()
+        : SkSurface_Base(T().imageInfo(), nullptr) {
     }
     SkCanvas* onNewCanvas() override {
-        mCanvas->ref();
-        return mCanvas;
+        return new T();
     }
     sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override {
         return sk_sp<SkSurface>();
@@ -215,8 +213,8 @@
     sk_sp<SkImage> onNewImageSnapshot(SkBudgeted, SkCopyPixelsMode) override {
         return sk_sp<SkImage>();
     }
+    T* canvas() { return static_cast<T*>(getCanvas()); }
     void onCopyOnWrite(ContentChangeMode) override {}
-    T* mCanvas;
 };
 }
 
@@ -281,10 +279,9 @@
     LayerUpdateQueue layerUpdateQueue;
     SkRect dirty = SkRect::MakeWH(800, 600);
     auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
-    sk_sp<DeferTestCanvas> canvas(new DeferTestCanvas());
-    sk_sp<SkSurface> surface(new DeferLayer<DeferTestCanvas>(canvas.get()));
+    sk_sp<DeferLayer<DeferTestCanvas>> surface(new DeferLayer<DeferTestCanvas>());
     pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, contentDrawBounds, surface);
-    EXPECT_EQ(4, canvas->mDrawCounter);
+    EXPECT_EQ(4, surface->canvas()->mDrawCounter);
 }
 
 RENDERTHREAD_TEST(SkiaPipeline, clipped) {
@@ -312,11 +309,10 @@
     LayerUpdateQueue layerUpdateQueue;
     SkRect dirty = SkRect::MakeLTRB(10, 20, 30, 40);
     auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
-    sk_sp<ClippedTestCanvas> canvas(new ClippedTestCanvas());
-    sk_sp<SkSurface> surface(new DeferLayer<ClippedTestCanvas>(canvas.get()));
+    sk_sp<DeferLayer<ClippedTestCanvas>> surface(new DeferLayer<ClippedTestCanvas>());
     pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true,
             SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface);
-    EXPECT_EQ(1, canvas->mDrawCounter);
+    EXPECT_EQ(1, surface->canvas()->mDrawCounter);
 }
 
 RENDERTHREAD_TEST(SkiaPipeline, clip_replace) {
@@ -328,11 +324,8 @@
         }
         void onDrawPaint(const SkPaint&) {
             EXPECT_EQ(0, mDrawCounter++);
-            //TODO: this unit test is failing on the commented check below, because of a missing
-            //feature. In Snapshot::applyClip HWUI is intersecting the clip with the clip root,
-            //even for kReplace_Op clips. We need to implement the same for Skia pipelines.
-            //EXPECT_EQ(SkRect::MakeLTRB(20, 10, 30, 40), TestUtils::getClipBounds(this)) //got instead 20 0 30 50
-            //        << "Expect resolved clip to be intersection of viewport clip and clip op";
+            EXPECT_EQ(SkRect::MakeLTRB(20, 10, 30, 40), TestUtils::getClipBounds(this))
+                    << "Expect resolved clip to be intersection of viewport clip and clip op";
         }
         int mDrawCounter = 0;
     };
@@ -340,16 +333,15 @@
     std::vector<sp<RenderNode>> nodes;
     nodes.push_back(TestUtils::createSkiaNode(20, 20, 30, 30,
             [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
-        canvas.clipRect(0, -20, 10, 30, kReplace_SkClipOp);
+        canvas.clipRect(0, -20, 10, 30, SkClipOp::kReplace);
         canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
     }));
 
     LayerUpdateQueue layerUpdateQueue;
     SkRect dirty = SkRect::MakeLTRB(10, 10, 40, 40);
     auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
-    sk_sp<ClipReplaceTestCanvas> canvas(new ClipReplaceTestCanvas());
-    sk_sp<SkSurface> surface(new DeferLayer<ClipReplaceTestCanvas>(canvas.get()));
+    sk_sp<DeferLayer<ClipReplaceTestCanvas>> surface(new DeferLayer<ClipReplaceTestCanvas>());
     pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true,
             SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface);
-    EXPECT_EQ(1, canvas->mDrawCounter);
+    EXPECT_EQ(1, surface->canvas()->mDrawCounter);
 }
diff --git a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
index ec2efc8..e7171c8 100644
--- a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
+++ b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
@@ -51,7 +51,7 @@
             EXPECT_EQ(mDrawCounter++, 0);
             mCallback(*this);
         }
-        void onClipRRect(const SkRRect& rrect, ClipOp op, ClipEdgeStyle style) {
+        void onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle style) {
             SkCanvas::onClipRRect(rrect, op, style);
         }
         std::function<void(const SkCanvas&)> mCallback;
@@ -65,10 +65,10 @@
         canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint);
     });
 
-    sk_sp<PropertyTestCanvas> canvas(new PropertyTestCanvas(opValidateCallback));
-    RenderNodeDrawable drawable(node.get(), canvas.get(), true);
-    canvas->drawDrawable(&drawable);
-    EXPECT_EQ(1, canvas->mDrawCounter);
+    PropertyTestCanvas canvas(opValidateCallback);
+    RenderNodeDrawable drawable(node.get(), &canvas, true);
+    canvas.drawDrawable(&drawable);
+    EXPECT_EQ(1, canvas.mDrawCounter);
 }
 
 }
diff --git a/libs/hwui/utils/TestWindowContext.cpp b/libs/hwui/utils/TestWindowContext.cpp
index 598cd1e..8b80d69 100644
--- a/libs/hwui/utils/TestWindowContext.cpp
+++ b/libs/hwui/utils/TestWindowContext.cpp
@@ -93,7 +93,7 @@
 
     SkCanvas* prepareToDraw() {
         //mCanvas->reset(mSize.width(), mSize.height());
-        mCanvas->clipRect(0, 0, mSize.width(), mSize.height(), kReplace_SkClipOp);
+        mCanvas->clipRect(0, 0, mSize.width(), mSize.height(), SkClipOp::kReplace);
         return mCanvas->asSkCanvas();
     }
 
diff --git a/libs/incident/Android.mk b/libs/incident/Android.mk
new file mode 100644
index 0000000..439e86d
--- /dev/null
+++ b/libs/incident/Android.mk
@@ -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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libincident
+
+LOCAL_CFLAGS := \
+        -Wall -Werror -Wno-missing-field-initializers -Wno-unused-variable -Wunused-parameter
+
+LOCAL_SHARED_LIBRARIES := \
+        libbinder \
+        liblog \
+        libutils
+
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/../../core/java
+LOCAL_C_INCLUDES := \
+        $(LOCAL_PATH)/include
+
+LOCAL_SRC_FILES := \
+        ../../core/java/android/os/IIncidentManager.aidl \
+        ../../core/java/android/os/IIncidentReportCompletedListener.aidl \
+        ../../core/java/android/os/IIncidentReportStatusListener.aidl \
+        src/IncidentReportArgs.cpp
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/libs/incident/include/android/os/IncidentReportArgs.h b/libs/incident/include/android/os/IncidentReportArgs.h
new file mode 100644
index 0000000..956ef6c
--- /dev/null
+++ b/libs/incident/include/android/os/IncidentReportArgs.h
@@ -0,0 +1,62 @@
+/**
+ * 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_DUMPSTATE_ARGS_H_
+#define ANDROID_OS_DUMPSTATE_ARGS_H_
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <utils/String16.h>
+
+#include <set>
+#include <vector>
+
+namespace android {
+namespace os {
+
+using namespace std;
+
+class IncidentReportArgs : public Parcelable {
+public:
+    IncidentReportArgs();
+    explicit IncidentReportArgs(const IncidentReportArgs& that);
+    virtual ~IncidentReportArgs();
+
+    virtual status_t writeToParcel(Parcel* out) const;
+    virtual status_t readFromParcel(const Parcel* in);
+
+    void setAll(bool all);
+    void addSection(int section);
+    void addHeader(const vector<int8_t>& header);
+
+    inline bool all() const { return mAll; };
+    bool containsSection(int section) const;
+
+    inline const set<int>& sections() const { return mSections; }
+    inline const vector<vector<int8_t>>& headers() const { return mHeaders; }
+
+    void merge(const IncidentReportArgs& that);
+
+private:
+    set<int> mSections;
+    vector<vector<int8_t>> mHeaders;
+    bool mAll;
+};
+
+}
+}
+
+#endif // ANDROID_OS_DUMPSTATE_ARGS_H_
diff --git a/libs/incident/proto/android/privacy.proto b/libs/incident/proto/android/privacy.proto
new file mode 100644
index 0000000..ae5af0e
--- /dev/null
+++ b/libs/incident/proto/android/privacy.proto
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+option java_package = "android";
+option java_multiple_files = true;
+
+import "google/protobuf/descriptor.proto";
+
+package android;
+
+// TODO: It's better to track this by semantic types and set policy for those.
+// Do this for now to bootstrap the tools.
+enum Destination {
+    // Fields or messages annotated with DEST_LOCAL must never be
+    // extracted from the device automatically. They can be accessed
+    // by tools on the developer's workstation, and if they are sent
+    // to another device that must be by the user, with a PII warning. (TBD)
+    DEST_LOCAL = 0;
+
+    // Fields or messages annotated with DEST_EXPLICIT can be sent
+    // off the device with an explicit user action.
+    DEST_EXPLICIT = 1;
+
+    // Fields or messages annotated with DEST_LOCAL can be sent by
+    // automatic means, without per-sending user consent. The user
+    // still must have previously accepted a consent to share this
+    // information.
+    DEST_AUTOMATIC = 2;
+
+    // There is no more permissive option than DEST_AUTOMATIC.
+}
+
+message PrivacyFlags {
+  optional Destination dest = 1  [
+      default = DEST_LOCAL
+  ];
+}
+
+extend google.protobuf.FieldOptions {
+    // Flags for automatically filtering statistics
+    optional PrivacyFlags privacy = 102672883;
+}
diff --git a/libs/incident/src/IncidentReportArgs.cpp b/libs/incident/src/IncidentReportArgs.cpp
new file mode 100644
index 0000000..f604909
--- /dev/null
+++ b/libs/incident/src/IncidentReportArgs.cpp
@@ -0,0 +1,172 @@
+/**
+ * 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_TAG "dumpstate"
+
+#include <android/os/IncidentReportArgs.h>
+
+#include <cutils/log.h>
+
+namespace android {
+namespace os {
+
+IncidentReportArgs::IncidentReportArgs()
+    :mSections(),
+     mAll(false)
+{
+}
+
+IncidentReportArgs::IncidentReportArgs(const IncidentReportArgs& that)
+    :mSections(that.mSections),
+     mHeaders(that.mHeaders),
+     mAll(that.mAll)
+{
+}
+
+IncidentReportArgs::~IncidentReportArgs()
+{
+}
+
+status_t
+IncidentReportArgs::writeToParcel(Parcel* out) const
+{
+    status_t err;
+
+    err = out->writeInt32(mAll);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    err = out->writeInt32(mSections.size());
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    for (set<int>::const_iterator it=mSections.begin(); it!=mSections.end(); it++) {
+        err = out->writeInt32(*it);
+        if (err != NO_ERROR) {
+            return err;
+        }
+    }
+
+    err = out->writeInt32(mHeaders.size());
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    for (vector<vector<int8_t>>::const_iterator it = mHeaders.begin(); it != mHeaders.end(); it++) {
+        err = out->writeByteVector(*it);
+        if (err != NO_ERROR) {
+            return err;
+        }
+    }
+
+    return NO_ERROR;
+}
+
+status_t
+IncidentReportArgs::readFromParcel(const Parcel* in)
+{
+    status_t err;
+
+    int32_t all;
+    err = in->readInt32(&all);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    if (all != 0) {
+        mAll = all;
+    }
+
+    mSections.clear();
+    int32_t sectionCount;
+    err = in->readInt32(&sectionCount);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    for (int i=0; i<sectionCount; i++) {
+        int32_t section;
+        err = in->readInt32(&section);
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+        mSections.insert(section);
+    }
+
+    int32_t headerCount;
+    err = in->readInt32(&headerCount);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    mHeaders.resize(headerCount);
+    for (int i=0; i<headerCount; i++) {
+        err = in->readByteVector(&mHeaders[i]);
+        if (err != NO_ERROR) {
+            return err;
+        }
+    }
+
+    return OK;
+}
+
+void
+IncidentReportArgs::setAll(bool all)
+{
+    mAll = all;
+    if (all) {
+        mSections.clear();
+    }
+}
+
+void
+IncidentReportArgs::addSection(int section)
+{
+    if (!mAll) {
+        mSections.insert(section);
+    }
+}
+
+void
+IncidentReportArgs::addHeader(const vector<int8_t>& header)
+{
+    mHeaders.push_back(header);
+}
+
+bool
+IncidentReportArgs::containsSection(int section) const
+{
+     return mAll || mSections.find(section) != mSections.end();
+}
+
+void
+IncidentReportArgs::merge(const IncidentReportArgs& that)
+{
+    if (mAll) {
+        return;
+    } else if (that.mAll) {
+        mAll = true;
+        mSections.clear();
+    } else {
+        for (set<int>::const_iterator it=that.mSections.begin();
+                it!=that.mSections.end(); it++) {
+            mSections.insert(*it);
+        }
+    }
+}
+
+}
+}
diff --git a/libs/services/Android.mk b/libs/services/Android.mk
new file mode 100644
index 0000000..cbfd4b3
--- /dev/null
+++ b/libs/services/Android.mk
@@ -0,0 +1,43 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+# Provides C++ wrappers for system services.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libservices
+LOCAL_SRC_FILES := \
+    ../../core/java/com/android/internal/os/IDropBoxManagerService.aidl \
+    src/os/DropBoxManager.cpp
+
+LOCAL_AIDL_INCLUDES := \
+    $(LOCAL_PATH)/../../core/java
+LOCAL_C_INCLUDES := \
+    system/core/include
+LOCAL_SHARED_LIBRARIES := \
+    libbinder \
+    liblog \
+    libcutils \
+    libutils
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
+
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+
+include $(BUILD_SHARED_LIBRARY)
+
+
diff --git a/libs/services/include/android/os/DropBoxManager.h b/libs/services/include/android/os/DropBoxManager.h
new file mode 100644
index 0000000..8717178
--- /dev/null
+++ b/libs/services/include/android/os/DropBoxManager.h
@@ -0,0 +1,94 @@
+/*
+ * 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_DROPBOXMANAGER_H
+#define _ANDROID_OS_DROPBOXMANAGER_H
+
+#include <android-base/unique_fd.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <binder/Status.h>
+#include <utils/RefBase.h>
+
+#include <vector>
+
+namespace android {
+namespace os {
+
+using namespace android;
+using namespace android::base;
+using namespace android::binder;
+using namespace std;
+
+class DropBoxManager : public virtual RefBase
+{
+public:
+    enum {
+        IS_EMPTY = 1,
+        IS_TEXT = 2,
+        IS_GZIPPED = 4
+    };
+
+    DropBoxManager();
+    virtual ~DropBoxManager();
+
+    static sp<DropBoxManager> create();
+
+    // Create a new entry with plain text contents.
+    Status addText(const String16& tag, const string& text);
+
+    // Create a new Entry with byte array contents. Makes a copy of the data.
+    Status addData(const String16& tag, uint8_t const* data, size_t size, int flags);
+
+    // Create a new Entry from a file. The file will be opened in this process
+    // and a handle will be passed to the system process, so no additional permissions
+    // are required from the system process.  Returns NULL if the file can't be opened.
+    Status addFile(const String16& tag, const string& filename, int flags);
+    
+    class Entry : public virtual RefBase, public Parcelable {
+    public:
+        Entry();
+        virtual ~Entry();
+
+        virtual status_t writeToParcel(Parcel* out) const;
+        virtual status_t readFromParcel(const Parcel* in);
+        
+    private:
+        Entry(const String16& tag, int32_t flags);
+        Entry(const String16& tag, int32_t flags, int fd);
+
+        String16 mTag;
+        int64_t mTimeMillis;
+        int32_t mFlags;
+
+        vector<uint8_t> mData;
+        unique_fd mFd;
+
+        friend class DropBoxManager;
+    };
+
+private:
+    enum {
+        HAS_BYTE_ARRAY = 8
+    };
+
+    Status add(const Entry& entry);
+};
+
+}} // namespace android::os
+
+#endif // _ANDROID_OS_DROPBOXMANAGER_H
+
diff --git a/libs/services/src/os/DropBoxManager.cpp b/libs/services/src/os/DropBoxManager.cpp
new file mode 100644
index 0000000..bbb45f0
--- /dev/null
+++ b/libs/services/src/os/DropBoxManager.cpp
@@ -0,0 +1,199 @@
+/*
+ * 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_TAG "DropBoxManager"
+
+#include <android/os/DropBoxManager.h>
+
+#include <binder/IServiceManager.h>
+#include <com/android/internal/os/IDropBoxManagerService.h>
+#include <cutils/log.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+namespace android {
+namespace os {
+
+using namespace ::com::android::internal::os;
+
+DropBoxManager::Entry::Entry()
+    :mTag(),
+     mTimeMillis(0),
+     mFlags(IS_EMPTY),
+     mData(),
+     mFd()
+{
+    mFlags = IS_EMPTY;
+}
+
+DropBoxManager::Entry::Entry(const String16& tag, int32_t flags)
+    :mTag(tag),
+     mTimeMillis(0),
+     mFlags(flags),
+     mData(),
+     mFd()
+{
+}
+
+DropBoxManager::Entry::Entry(const String16& tag, int32_t flags, int fd)
+    :mTag(tag),
+     mTimeMillis(0),
+     mFlags(flags),
+     mData(),
+     mFd(fd)
+{
+}
+
+DropBoxManager::Entry::~Entry()
+{
+}
+
+status_t
+DropBoxManager::Entry::writeToParcel(Parcel* out) const
+{
+    status_t err;
+
+    err = out->writeString16(mTag);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    err = out->writeInt64(mTimeMillis);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    if (mFd.get() != -1) {
+        err = out->writeInt32(mFlags & ~HAS_BYTE_ARRAY);  // Clear bit just to be safe
+        if (err != NO_ERROR) {
+            return err;
+        }
+        ALOGD("writing fd %d\n", mFd.get());
+        err = out->writeParcelFileDescriptor(mFd);
+        if (err != NO_ERROR) {
+            return err;
+        }
+    } else {
+        err = out->writeInt32(mFlags | HAS_BYTE_ARRAY);
+        if (err != NO_ERROR) {
+            return err;
+        }
+        err = out->writeByteVector(mData);
+        if (err != NO_ERROR) {
+            return err;
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t
+DropBoxManager::Entry::readFromParcel(const Parcel* in)
+{
+    status_t err;
+
+    err = in->readString16(&mTag);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    err = in->readInt64(&mTimeMillis);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    err = in->readInt32(&mFlags);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    if ((mFlags & HAS_BYTE_ARRAY) != 0) {
+        err = in->readByteVector(&mData);
+        if (err != NO_ERROR) {
+            return err;
+        }
+        mFlags &= ~HAS_BYTE_ARRAY;
+    } else {
+        int fd;
+        fd = in->readParcelFileDescriptor();
+        if (fd == -1) {
+            return EBADF;
+        }
+        fd = dup(fd);
+        if (fd == -1) {
+            return errno;
+        }
+        mFd.reset(fd);
+    }
+
+    return NO_ERROR;
+}
+
+
+DropBoxManager::DropBoxManager()
+{
+}
+
+DropBoxManager::~DropBoxManager()
+{
+}
+
+Status
+DropBoxManager::addText(const String16& tag, const string& text)
+{
+    Entry entry(tag, IS_TEXT);
+    entry.mData.assign(text.c_str(), text.c_str() + text.size());
+    return add(entry);
+}
+
+Status
+DropBoxManager::addData(const String16& tag, uint8_t const* data,
+        size_t size, int flags)
+{
+    Entry entry(tag, flags);
+    entry.mData.assign(data, data+size);
+    return add(entry);
+}
+
+Status
+DropBoxManager::addFile(const String16& tag, const string& filename, int flags)
+{
+    int fd = open(filename.c_str(), O_RDONLY);
+    if (fd == -1) {
+        string message("addFile can't open file: ");
+        message += filename;
+        ALOGW("DropboxManager: %s", message.c_str());
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, message.c_str());
+    }
+
+    Entry entry(tag, flags, fd);
+    return add(entry);
+}
+
+Status
+DropBoxManager::add(const Entry& entry)
+{
+    sp<IDropBoxManagerService> service = interface_cast<IDropBoxManagerService>(
+        defaultServiceManager()->getService(android::String16("dropbox")));
+    if (service == NULL) {
+        return Status::fromExceptionCode(Status::EX_NULL_POINTER, "can't find dropbox service");
+    }
+    return service->add(entry);
+}
+
+}} // namespace android::os
+
diff --git a/libs/storage/Android.bp b/libs/storage/Android.bp
new file mode 100644
index 0000000..911bd1d
--- /dev/null
+++ b/libs/storage/Android.bp
@@ -0,0 +1,19 @@
+cc_library_static {
+    name: "libstorage",
+
+    srcs: [
+        "IMountServiceListener.cpp",
+        "IMountShutdownObserver.cpp",
+        "IObbActionListener.cpp",
+        "IMountService.cpp",
+    ],
+
+    export_include_dirs: ["include"],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    shared_libs: ["libbinder"],
+}
diff --git a/libs/storage/Android.mk b/libs/storage/Android.mk
deleted file mode 100644
index d0eb6d4..0000000
--- a/libs/storage/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	IMountServiceListener.cpp \
-	IMountShutdownObserver.cpp \
-	IObbActionListener.cpp \
-	IMountService.cpp
-
-LOCAL_MODULE:= libstorage
-
-LOCAL_CFLAGS += -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := libbinder
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/include/storage/IMountService.h b/libs/storage/include/storage/IMountService.h
similarity index 100%
rename from include/storage/IMountService.h
rename to libs/storage/include/storage/IMountService.h
diff --git a/include/storage/IMountServiceListener.h b/libs/storage/include/storage/IMountServiceListener.h
similarity index 100%
rename from include/storage/IMountServiceListener.h
rename to libs/storage/include/storage/IMountServiceListener.h
diff --git a/include/storage/IMountShutdownObserver.h b/libs/storage/include/storage/IMountShutdownObserver.h
similarity index 100%
rename from include/storage/IMountShutdownObserver.h
rename to libs/storage/include/storage/IMountShutdownObserver.h
diff --git a/include/storage/IObbActionListener.h b/libs/storage/include/storage/IObbActionListener.h
similarity index 100%
rename from include/storage/IObbActionListener.h
rename to libs/storage/include/storage/IObbActionListener.h
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index 957c2d6..81db37e 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -109,13 +109,13 @@
     private IMediaBrowserServiceCallbacks mServiceCallbacks;
 
     /**
-     * Creates a media browser for the specified media browse service.
+     * Creates a media browser for the specified media browser service.
      *
      * @param context The context.
-     * @param serviceComponent The component name of the media browse service.
+     * @param serviceComponent The component name of the media browser service.
      * @param callback The connection callback.
      * @param rootHints An optional bundle of service-specific arguments to send
-     * to the media browse service when connecting and retrieving the root id
+     * to the media browser service when connecting and retrieving the root id
      * for browsing, or null if none. The contents of this bundle may affect
      * the information returned when browsing.
      * @see android.service.media.MediaBrowserService.BrowserRoot#EXTRA_RECENT
@@ -140,7 +140,7 @@
     }
 
     /**
-     * Connects to the media browse service.
+     * Connects to the media browser service.
      * <p>
      * The connection callback specified in the constructor will be invoked
      * when the connection completes or fails.
@@ -206,7 +206,7 @@
     }
 
     /**
-     * Disconnects from the media browse service.
+     * Disconnects from the media browser service.
      * After this, no more callbacks will be received.
      */
     public void disconnect() {
@@ -362,7 +362,7 @@
      *
      * @param parentId The id of the parent media item whose list of children
      *            will be subscribed.
-     * @param options A bundle of service-specific arguments to send to the media
+     * @param options The bundle of service-specific arguments to send to the media
      *            browse service. The contents of this bundle may affect the
      *            information returned when browsing.
      * @param callback The callback to receive the list of children.
@@ -370,7 +370,7 @@
     public void subscribe(@NonNull String parentId, @NonNull Bundle options,
             @NonNull SubscriptionCallback callback) {
         if (options == null) {
-            throw new IllegalArgumentException("options are null");
+            throw new IllegalArgumentException("options cannot be null");
         }
         subscribeInternal(parentId, new Bundle(options), callback);
     }
@@ -398,11 +398,11 @@
      *
      * @param parentId The id of the parent media item whose list of children
      *            will be unsubscribed.
-     * @param callback A callback sent to the media browse service to subscribe.
+     * @param callback A callback sent to the media browser service to subscribe.
      */
     public void unsubscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
         if (callback == null) {
-            throw new IllegalArgumentException("callback is null");
+            throw new IllegalArgumentException("callback cannot be null");
         }
         unsubscribeInternal(parentId, callback);
     }
@@ -417,10 +417,10 @@
      */
     public void getItem(final @NonNull String mediaId, @NonNull final ItemCallback cb) {
         if (TextUtils.isEmpty(mediaId)) {
-            throw new IllegalArgumentException("mediaId is empty.");
+            throw new IllegalArgumentException("mediaId cannot be empty.");
         }
         if (cb == null) {
-            throw new IllegalArgumentException("cb is null.");
+            throw new IllegalArgumentException("cb cannot be null.");
         }
         if (mState != CONNECT_STATE_CONNECTED) {
             Log.i(TAG, "Not connected, unable to retrieve the MediaItem.");
@@ -451,7 +451,7 @@
         try {
             mServiceBinder.getMediaItem(mediaId, receiver, mServiceCallbacks);
         } catch (RemoteException e) {
-            Log.i(TAG, "Remote error getting media item.");
+            Log.i(TAG, "Remote error getting media item.", e);
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
@@ -461,13 +461,74 @@
         }
     }
 
+    /**
+     * Searches {@link MediaItem media items} from the connected service. Not
+     * all services may support this, and {@link SearchCallback#onError} will be
+     * called if not implemented.
+     *
+     * @param query The search query that contains keywords separated by space. Should not be
+     *            an empty string.
+     * @param extras The bundle of service-specific arguments to send to the media browser
+     *            service. The contents of this bundle may affect the search result.
+     * @param callback The callback to receive the search result.
+     */
+    public void search(@NonNull final String query, final Bundle extras, SearchCallback callback) {
+        if (TextUtils.isEmpty(query)) {
+            throw new IllegalArgumentException("query cannot be empty.");
+        }
+        if (callback == null) {
+            throw new IllegalArgumentException("callback cannot be null.");
+        }
+        if (mState != CONNECT_STATE_CONNECTED) {
+            Log.i(TAG, "Not connected, unable to search.");
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onError(query, extras);
+                }
+            });
+            return;
+        }
+        ResultReceiver receiver = new ResultReceiver(mHandler) {
+            @Override
+            protected void onReceiveResult(int resultCode, Bundle resultData) {
+                if (resultCode != 0 || resultData == null
+                        || !resultData.containsKey(MediaBrowserService.KEY_SEARCH_RESULTS)) {
+                    callback.onError(query, extras);
+                    return;
+                }
+                Parcelable[] items = resultData.getParcelableArray(
+                        MediaBrowserService.KEY_SEARCH_RESULTS);
+                List<MediaItem> results = null;
+                if (items != null) {
+                    results = new ArrayList<>();
+                    for (Parcelable item : items) {
+                        results.add((MediaItem) item);
+                    }
+                }
+                callback.onSearchResult(query, extras, results);
+            }
+        };
+        try {
+            mServiceBinder.search(query, extras, receiver, mServiceCallbacks);
+        } catch (RemoteException e) {
+            Log.i(TAG, "Remote error getting media item.", e);
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onError(query, extras);
+                }
+            });
+        }
+    }
+
     private void subscribeInternal(String parentId, Bundle options, SubscriptionCallback callback) {
         // Check arguments.
         if (TextUtils.isEmpty(parentId)) {
-            throw new IllegalArgumentException("parentId is empty.");
+            throw new IllegalArgumentException("parentId cannot be empty.");
         }
         if (callback == null) {
-            throw new IllegalArgumentException("callback is null");
+            throw new IllegalArgumentException("callback cannot be null");
         }
         // Update or create the subscription.
         Subscription sub = mSubscriptions.get(parentId);
@@ -497,7 +558,7 @@
     private void unsubscribeInternal(String parentId, SubscriptionCallback callback) {
         // Check arguments.
         if (TextUtils.isEmpty(parentId)) {
-            throw new IllegalArgumentException("parentId is empty.");
+            throw new IllegalArgumentException("parentId cannot be empty.");
         }
 
         Subscription sub = mSubscriptions.get(parentId);
@@ -712,7 +773,9 @@
     }
 
     /**
-     * A class with information on a single media item for use in browsing media.
+     * A class with information on a single media item for use in browsing/searching media.
+     * MediaItems are application dependent so we cannot guarantee that they contain the
+     * right values.
      */
     public static class MediaItem implements Parcelable {
         private final int mFlags;
@@ -830,7 +893,7 @@
          * Returns the media id in the {@link MediaDescription} for this item.
          * @see android.media.MediaMetadata#METADATA_KEY_MEDIA_ID
          */
-        public @NonNull String getMediaId() {
+        public @Nullable String getMediaId() {
             return mDescription.getMediaId();
         }
     }
@@ -882,7 +945,7 @@
          *
          * @param parentId The media id of the parent media item.
          * @param children The children which were loaded.
-         * @param options A bundle of service-specific arguments sent to the media
+         * @param options The bundle of service-specific arguments sent to the media
          *            browse service. The contents of this bundle may affect the
          *            information returned when browsing.
          */
@@ -912,8 +975,8 @@
          *
          * @param parentId The media id of the parent media item whose children could
          *            not be loaded.
-         * @param options A bundle of service-specific arguments sent to the media
-         *            browse service.
+         * @param options The bundle of service-specific arguments sent to the media
+         *            browser service.
          */
         public void onError(@NonNull String parentId, @NonNull Bundle options) {
         }
@@ -924,7 +987,7 @@
      */
     public static abstract class ItemCallback {
         /**
-         * Called when the item has been returned by the browser service.
+         * Called when the item has been returned by the connected service.
          *
          * @param item The item that was returned or null if it doesn't exist.
          */
@@ -932,11 +995,38 @@
         }
 
         /**
-         * Called when the item doesn't exist or there was an error retrieving it.
+         * Called there was an error retrieving it or the connected service doesn't support
+         * {@link #getItem}.
          *
-         * @param itemId The media id of the media item which could not be loaded.
+         * @param mediaId The media id of the media item which could not be loaded.
          */
-        public void onError(@NonNull String itemId) {
+        public void onError(@NonNull String mediaId) {
+        }
+    }
+
+    /**
+     * Callback for receiving the result of {@link #search}.
+     */
+    public static abstract class SearchCallback {
+        /**
+         * Called when the {@link #search} finished successfully.
+         *
+         * @param query The search query sent for the search request to the connected service.
+         * @param extras The bundle of service-specific arguments sent to the connected service.
+         * @param items The list of media items which contains the search result.
+         */
+        public void onSearchResult(@NonNull String query, Bundle extras,
+                @NonNull List<MediaItem> items) {
+        }
+
+        /**
+         * Called when an error happens while {@link #search} or the connected service doesn't
+         * support {@link #search}.
+         *
+         * @param query The search query sent for the search request to the connected service.
+         * @param extras The bundle of service-specific arguments sent to the connected service.
+         */
+        public void onError(@NonNull String query, Bundle extras) {
         }
     }
 
diff --git a/media/java/android/mtp/MtpServer.java b/media/java/android/mtp/MtpServer.java
index 99f93e4..9801949 100644
--- a/media/java/android/mtp/MtpServer.java
+++ b/media/java/android/mtp/MtpServer.java
@@ -72,6 +72,11 @@
         native_remove_storage(storage.getStorageId());
     }
 
+    public static void configure(boolean usePtp) {
+        native_configure(usePtp);
+    }
+
+    public static native final void native_configure(boolean usePtp);
     private native final void native_setup(MtpDatabase database, boolean usePtp);
     private native final void native_run();
     private native final void native_cleanup();
diff --git a/media/java/android/service/media/IMediaBrowserService.aidl b/media/java/android/service/media/IMediaBrowserService.aidl
index 84f41f6..e95154f 100644
--- a/media/java/android/service/media/IMediaBrowserService.aidl
+++ b/media/java/android/service/media/IMediaBrowserService.aidl
@@ -19,8 +19,10 @@
 
     void addSubscriptionDeprecated(String uri, IMediaBrowserServiceCallbacks callbacks);
     void removeSubscriptionDeprecated(String uri, IMediaBrowserServiceCallbacks callbacks);
-
     void getMediaItem(String uri, in ResultReceiver cb, IMediaBrowserServiceCallbacks callbacks);
+    void search(String query, in Bundle extras, in ResultReceiver cb,
+            IMediaBrowserServiceCallbacks callbacks);
+
     void addSubscription(String uri, in IBinder token, in Bundle options,
             IMediaBrowserServiceCallbacks callbacks);
     void removeSubscription(String uri, in IBinder token, IMediaBrowserServiceCallbacks callbacks);
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index a19e347..16847c1 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -52,9 +52,9 @@
 import java.util.List;
 
 /**
- * Base class for media browse services.
+ * Base class for media browser services.
  * <p>
- * Media browse services enable applications to browse media content provided by an application
+ * Media browser services enable applications to browse media content provided by an application
  * and ask the application to start playing it. They may also be used to control content that
  * is already playing by way of a {@link MediaSession}.
  * </p>
@@ -85,18 +85,27 @@
 
     /**
      * A key for passing the MediaItem to the ResultReceiver in getItem.
-     *
      * @hide
      */
     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;
+    /**
+     * A key for passing the list of MediaItems to the ResultReceiver in search.
+     * @hide
+     */
+    public static final String KEY_SEARCH_RESULTS = "search_results";
+
+    private static final int RESULT_FLAG_OPTION_NOT_HANDLED = 1 << 0;
+    private static final int RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED = 1 << 1;
+    private static final int RESULT_FLAG_ON_SEARCH_NOT_IMPLEMENTED = 1 << 2;
+
+    private static final int RESULT_ERROR = -1;
+    private static final int RESULT_OK = 0;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(flag=true, value = { RESULT_FLAG_OPTION_NOT_HANDLED,
-            RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED })
+            RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED, RESULT_FLAG_ON_SEARCH_NOT_IMPLEMENTED })
     private @interface ResultFlags { }
 
     private final ArrayMap<IBinder, ConnectionRecord> mConnections = new ArrayMap<>();
@@ -307,10 +316,6 @@
         @Override
         public void getMediaItem(final String mediaId, final ResultReceiver receiver,
                 final IMediaBrowserServiceCallbacks callbacks) {
-            if (TextUtils.isEmpty(mediaId) || receiver == null) {
-                return;
-            }
-
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
@@ -324,6 +329,23 @@
                 }
             });
         }
+
+        @Override
+        public void search(final String query, Bundle extras, ResultReceiver receiver,
+                final IMediaBrowserServiceCallbacks callbacks) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    final IBinder b = callbacks.asBinder();
+                    ConnectionRecord connection = mConnections.get(b);
+                    if (connection == null) {
+                        Log.w(TAG, "search for callback that isn't registered query=" + query);
+                        return;
+                    }
+                    performSearch(query, extras, connection, receiver);
+                }
+            });
+        }
     }
 
     @Override
@@ -358,7 +380,7 @@
      * @param clientUid The uid of the application which is requesting access to
      *            browse media.
      * @param rootHints An optional bundle of service-specific arguments to send
-     *            to the media browse service when connecting and retrieving the
+     *            to the media browser service when connecting and retrieving the
      *            root id for browsing, or null if none. The contents of this
      *            bundle may affect the information returned when browsing.
      * @return The {@link BrowserRoot} for accessing this app's content or null.
@@ -412,8 +434,8 @@
      * @param parentId The id of the parent media item whose children are to be
      *            queried.
      * @param result The Result to send the list of children to.
-     * @param options A bundle of service-specific arguments sent from the media
-     *            browse. The information returned through the result should be
+     * @param options The bundle of service-specific arguments sent from the media
+     *            browser. The information returned through the result should be
      *            affected by the contents of this bundle.
      */
     public void onLoadChildren(@NonNull String parentId,
@@ -450,6 +472,32 @@
     }
 
     /**
+     * Called to get the search result.
+     * <p>
+     * Implementations must call {@link Result#sendResult result.sendResult}. If
+     * the search will be an expensive operation {@link Result#detach result.detach}
+     * may be called before returning from this function, and then {@link Result#sendResult
+     * result.sendResult} called when the search has been completed.
+     * </p><p>
+     * In case there are no search results, call {@link Result#sendResult} with an empty list.
+     * In case there are some errors happened, call {@link Result#sendResult result.sendResult}
+     * with {@code null}, which will invoke {@link MediaBrowser.SearchCallback#onError}.
+     * </p><p>
+     * The default implementation will invoke {@link MediaBrowser.SearchCallback#onError}.
+     * </p>
+     *
+     * @param query The search query sent from the media browser. It contains keywords separated
+     *            by space.
+     * @param extras The bundle of service-specific arguments sent from the media browser.
+     * @param result The {@link Result} to send the search result.
+     */
+    public void onSearch(@NonNull String query, Bundle extras,
+            Result<List<MediaBrowser.MediaItem>> result) {
+        result.setFlags(RESULT_FLAG_ON_SEARCH_NOT_IMPLEMENTED);
+        result.sendResult(null);
+    }
+
+    /**
      * Call to set the media session.
      * <p>
      * This should be called as soon as possible during the service's startup.
@@ -531,8 +579,8 @@
      *
      * @param parentId The id of the parent media item whose
      *            children changed.
-     * @param options A bundle of service-specific arguments to send
-     *            to the media browse. The contents of this bundle may
+     * @param options The bundle of service-specific arguments to send
+     *            to the media browser. The contents of this bundle may
      *            contain the information about the change.
      */
     public void notifyChildrenChanged(@NonNull String parentId, @NonNull Bundle options) {
@@ -705,12 +753,12 @@
             @Override
             void onResultSent(MediaBrowser.MediaItem item, @ResultFlags int flag) {
                 if ((flag & RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED) != 0) {
-                    receiver.send(-1, null);
+                    receiver.send(RESULT_ERROR, null);
                     return;
                 }
                 Bundle bundle = new Bundle();
                 bundle.putParcelable(KEY_MEDIA_ITEM, item);
-                receiver.send(0, bundle);
+                receiver.send(RESULT_OK, bundle);
             }
         };
 
@@ -724,6 +772,34 @@
         }
     }
 
+    private void performSearch(String query, Bundle extras, final ConnectionRecord connection,
+            final ResultReceiver receiver) {
+        final Result<List<MediaBrowser.MediaItem>> result =
+                new Result<List<MediaBrowser.MediaItem>>(query) {
+            @Override
+            void onResultSent(List<MediaBrowser.MediaItem> items, @ResultFlags int flag) {
+                if ((flag & RESULT_FLAG_ON_SEARCH_NOT_IMPLEMENTED) != 0
+                        || items == null) {
+                    receiver.send(RESULT_ERROR, null);
+                    return;
+                }
+                Bundle bundle = new Bundle();
+                bundle.putParcelableArray(KEY_SEARCH_RESULTS,
+                        items.toArray(new MediaBrowser.MediaItem[0]));
+                receiver.send(RESULT_OK, bundle);
+            }
+        };
+
+        mCurConnection = connection;
+        onSearch(query, extras, result);
+        mCurConnection = null;
+
+        if (!result.isDone()) {
+            throw new IllegalStateException("onSearch must call detach() or sendResult()"
+                    + " before returning for query=" + query);
+        }
+    }
+
     /**
      * Contains information that the browser service needs to send to the client
      * when first connected.
diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp
index d13187c..afd3082 100644
--- a/media/jni/android_mtp_MtpServer.cpp
+++ b/media/jni/android_mtp_MtpServer.cpp
@@ -56,17 +56,16 @@
     return (MtpServer*)env->GetLongField(thiz, field_MtpServer_nativeContext);
 }
 
+static void android_mtp_configure(JNIEnv *, jobject, jboolean usePtp) {
+    MtpServer::configure(usePtp);
+}
+
 static void
 android_mtp_MtpServer_setup(JNIEnv *env, jobject thiz, jobject javaDatabase, jboolean usePtp)
 {
-    int fd = open("/dev/mtp_usb", O_RDWR);
-    if (fd >= 0) {
-        MtpServer* server = new MtpServer(fd, getMtpDatabase(env, javaDatabase),
-                usePtp, AID_MEDIA_RW, 0664, 0775);
-        env->SetLongField(thiz, field_MtpServer_nativeContext, (jlong)server);
-    } else {
-        ALOGE("could not open MTP driver, errno: %d", errno);
-    }
+    MtpServer* server = new MtpServer(getMtpDatabase(env, javaDatabase),
+            usePtp, AID_MEDIA_RW, 0664, 0775);
+    env->SetLongField(thiz, field_MtpServer_nativeContext, (jlong)server);
 }
 
 static void
@@ -180,6 +179,7 @@
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gMethods[] = {
+    {"native_configure",              "(Z)V",  (void *)android_mtp_configure},
     {"native_setup",                "(Landroid/mtp/MtpDatabase;Z)V",
                                             (void *)android_mtp_MtpServer_setup},
     {"native_run",                  "()V",  (void *)android_mtp_MtpServer_run},
diff --git a/media/mca/filterfw/native/core/shader_program.cpp b/media/mca/filterfw/native/core/shader_program.cpp
index 1e573fb..d460512 100644
--- a/media/mca/filterfw/native/core/shader_program.cpp
+++ b/media/mca/filterfw/native/core/shader_program.cpp
@@ -1028,7 +1028,11 @@
   attrib.values = data_cpy;
   attrib.owned_data = data_cpy; // Marks this for deletion later on
 
-  return StoreAttribute(attrib);
+  if (StoreAttribute(attrib))
+    return true;
+  // If storing this failed, then it won't be deleted on its own.
+  delete[] data_cpy;
+  return false;
 }
 
 bool ShaderProgram::StoreAttribute(VertexAttrib attrib) {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkIntegrationTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkIntegrationTestRunner.java
index 7751fcc..6511cc8 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkIntegrationTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkIntegrationTestRunner.java
@@ -38,7 +38,7 @@
 
     private static final String TAG = "MediaFrameworkIntegrationTestRunner";
 
-    public static int mCameraId = 0;
+    public static String mCameraId = "0";
 
     @Override
     public TestSuite getAllTests() {
@@ -62,7 +62,7 @@
             try {
                 Log.v(TAG,
                         String.format("Reading camera_id from icicle: '%s'", cameraId));
-                mCameraId = Integer.parseInt(cameraId);
+                mCameraId = cameraId;
             }
             catch (NumberFormatException e) {
                 Log.e(TAG, String.format("Failed to convert camera_id to integer"));
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index 4f2fdff..fcb861c 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -116,8 +116,8 @@
     @SmallTest
     public void testSupportsCamera2Api() throws Exception {
         for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
-
-            boolean supports = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_2);
+            boolean supports = mUtils.getCameraService().supportsCameraApi(
+                String.valueOf(cameraId), API_VERSION_2);
 
             Log.v(TAG, "Camera " + cameraId + " supports api2: " + supports);
         }
@@ -128,7 +128,8 @@
     public void testSupportsCamera1Api() throws Exception {
         for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
 
-            boolean supports = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_1);
+            boolean supports = mUtils.getCameraService().supportsCameraApi(
+                String.valueOf(cameraId), API_VERSION_1);
             assertTrue(
                     "Camera service returned false when queried if it supports camera1 api " +
                     " for camera ID " + cameraId, supports);
@@ -285,7 +286,7 @@
 
             ICameraDeviceUser cameraUser =
                     mUtils.getCameraService().connectDevice(
-                        dummyCallbacks, cameraId,
+                        dummyCallbacks, String.valueOf(cameraId),
                         clientPackageName,
                         ICameraService.USE_CALLING_UID);
             assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
@@ -298,9 +299,9 @@
 
     static class DummyCameraServiceListener extends ICameraServiceListener.Stub {
         @Override
-        public void onStatusChanged(int status, int cameraId)
+        public void onStatusChanged(int status, String cameraId)
                 throws RemoteException {
-            Log.v(TAG, String.format("Camera %d has status changed to 0x%x", cameraId, status));
+            Log.v(TAG, String.format("Camera %s has status changed to 0x%x", cameraId, status));
         }
         public void onTorchStatusChanged(int status, String cameraId)
                 throws RemoteException {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 832363c..9a78544 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -66,7 +66,7 @@
     private static final int DEFAULT_IMAGE_HEIGHT = 480;
     private static final int MAX_NUM_IMAGES = 5;
 
-    private int mCameraId;
+    private String mCameraId;
     private ICameraDeviceUser mCameraUser;
     private CameraBinderTestUtils mUtils;
     private ICameraDeviceCallbacks.Stub mMockCb;
diff --git a/packages/BackupRestoreConfirmation/res/values-si-rLK/strings.xml b/packages/BackupRestoreConfirmation/res/values-si-rLK/strings.xml
index aaeaf04..cbc130d 100644
--- a/packages/BackupRestoreConfirmation/res/values-si-rLK/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-si-rLK/strings.xml
@@ -29,7 +29,7 @@
     <string name="device_encryption_backup_text" msgid="5866590762672844664">"කරුණාකර ඔබගේ උපාංගයේ සංකේතන මුරපදය පහත ඇතුලත් කරන්න. සංරක්ෂිත උපස්ථ සංකේතනය කිරීමට මෙය භාවිත කළ හැක."</string>
     <string name="backup_enc_password_text" msgid="4981585714795233099">"කරුණාකර සියලු උපස්ථ දත්ත සංකේතනය කිරීම සඳහා භාවිතයට මුරපදයක් ඇතුළත් කරන්න. මෙය හිස්ව තැබුවොත්, ඔබගේ වර්තමාන උපස්ථ මුරපදය භාවිත වෙයි:"</string>
     <string name="backup_enc_password_optional" msgid="1350137345907579306">"සියලු උපස්ථ දත්ත සංකේතනය කිරීමට ඔබ අදහස් කරන්නේ නම්, මුරපදය පහලින් ඇතුලත් කරන්න:"</string>
-    <string name="backup_enc_password_required" msgid="7889652203371654149">"ඔබගේ උපාංගය සංකේතනය කර තිබෙන නිසා, ඔබගේ උපස්ථය සංකේතනය ඔබට අවශ්‍ය වී තිබේ. කරුණාකර මුරපදය පහළින් එකතු කරන්න:"</string>
+    <string name="backup_enc_password_required" msgid="7889652203371654149">"ඔබගේ උපාංගය සංකේතනය කර තිබෙන නිසා, ඔබගේ උපස්ථය සංකේතනය ඔබට අවශ්‍ය වී තිබේ. මුරපදය පහළින් එක් කරන්න:"</string>
     <string name="restore_enc_password_text" msgid="6140898525580710823">"යළි පිහිටුවන දත්ත සංකේතනය කරන ලද ඒවානම්, කරුණාකර මුරපදය පහලින් ඇතුල් කරන්න:"</string>
     <string name="toast_backup_started" msgid="550354281452756121">"උපස්ථ කිරීම ආරම්භ කරමින්..."</string>
     <string name="toast_backup_ended" msgid="3818080769548726424">"උපස්ථය අවසන්"</string>
diff --git a/packages/PrintSpooler/res/values-si-rLK/strings.xml b/packages/PrintSpooler/res/values-si-rLK/strings.xml
index ffff8e0..e661f93 100644
--- a/packages/PrintSpooler/res/values-si-rLK/strings.xml
+++ b/packages/PrintSpooler/res/values-si-rLK/strings.xml
@@ -52,7 +52,7 @@
     <string name="add_print_service_label" msgid="5356702546188981940">"සේවාව එක් කිරීම"</string>
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"සෙවීම් කොටුව පෙන්වන ලදී"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"සෙවීම් කොටුව සඟවන ලදී"</string>
-    <string name="print_add_printer" msgid="1088656468360653455">"මුද්‍රණ යන්ත්‍ර එකතු කරන්න"</string>
+    <string name="print_add_printer" msgid="1088656468360653455">"මුද්‍රණ යන්ත්‍ර එක් කරන්න"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"මුද්‍රකය තේරීම"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"මුද්‍රකය අමතක කිරීම"</string>
     <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
diff --git a/packages/SettingsLib/res/drawable/ic_menu.xml b/packages/SettingsLib/res/drawable/ic_menu.xml
index 910a3d0..b77db08 100644
--- a/packages/SettingsLib/res/drawable/ic_menu.xml
+++ b/packages/SettingsLib/res/drawable/ic_menu.xml
@@ -17,7 +17,8 @@
         android:width="24.0dp"
         android:height="24.0dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
+        android:viewportHeight="24.0"
+        android:tint="?android:attr/colorControlNormal">
     <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M3.0,18.0l18.0,0.0l0.0,-2.0L3.0,16.0l0.0,2.0zm0.0,-5.0l18.0,0.0l0.0,-2.0L3.0,11.0l0.0,2.0zm0.0,-7.0l0.0,2.0l18.0,0.0L21.0,6.0L3.0,6.0z"/>
diff --git a/packages/SettingsLib/res/layout/restricted_switch_preference.xml b/packages/SettingsLib/res/layout/restricted_switch_preference.xml
index bb1d906..0e4ef6b 100644
--- a/packages/SettingsLib/res/layout/restricted_switch_preference.xml
+++ b/packages/SettingsLib/res/layout/restricted_switch_preference.xml
@@ -24,7 +24,7 @@
     android:clipToPadding="false">
 
     <LinearLayout
-        android:id="@+id/icon_frame"
+        android:id="@+id/icon_container"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:minWidth="60dp"
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 4353282..2d89b00 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -31,7 +31,7 @@
     <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_wfa" msgid="3805736726317410714">"Conectado a través del asistente de Wi‑Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado a través de %1$s"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"Disponible a través de %1$s"</string>
     <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Conexión sin Internet"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index 6bd8a87..99d7f1e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -16,6 +16,7 @@
 
 package com.android.settingslib;
 
+import android.annotation.UserIdInt;
 import android.app.AppGlobals;
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
@@ -118,21 +119,25 @@
      */
     public static EnforcedAdmin checkIfKeyguardFeaturesDisabled(Context context,
             int keyguardFeatures, int userId) {
+        final LockSettingCheck check =
+                (DevicePolicyManager dpm, ComponentName admin, @UserIdInt int checkUser) ->
+                        (dpm.getKeyguardDisabledFeatures(admin, checkUser) & keyguardFeatures) != 0;
+
         final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
                 Context.DEVICE_POLICY_SERVICE);
         if (dpm == null) {
             return null;
         }
+
         final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
-        LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
-        EnforcedAdmin enforcedAdmin = null;
         if (um.getUserInfo(userId).isManagedProfile()) {
             final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userId);
             if (admins == null) {
                 return null;
             }
+            EnforcedAdmin enforcedAdmin = null;
             for (ComponentName admin : admins) {
-                if ((dpm.getKeyguardDisabledFeatures(admin, userId) & keyguardFeatures) != 0) {
+                if (check.isEnforcing(dpm, admin, userId)) {
                     if (enforcedAdmin == null) {
                         enforcedAdmin = new EnforcedAdmin(admin, userId);
                     } else {
@@ -140,49 +145,10 @@
                     }
                 }
             }
+            return enforcedAdmin;
         } else {
-            // Consider all admins for this user and the profiles that are visible from this
-            // user that do not use a separate work challenge.
-            for (UserInfo userInfo : um.getProfiles(userId)) {
-                final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userInfo.id);
-                if (admins == null) {
-                    continue;
-                }
-                final boolean isSeparateProfileChallengeEnabled =
-                        lockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id);
-                for (ComponentName admin : admins) {
-                    if (!isSeparateProfileChallengeEnabled) {
-                        if ((dpm.getKeyguardDisabledFeatures(admin, userInfo.id)
-                                    & keyguardFeatures) != 0) {
-                            if (enforcedAdmin == null) {
-                                enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
-                            } else {
-                                return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
-                            }
-                            // This same admins could have set policies both on the managed profile
-                            // and on the parent. So, if the admin has set the policy on the
-                            // managed profile here, we don't need to further check if that admin
-                            // has set policy on the parent admin.
-                            continue;
-                        }
-                    }
-                    if (userInfo.isManagedProfile()) {
-                        // If userInfo.id is a managed profile, we also need to look at
-                        // the policies set on the parent.
-                        DevicePolicyManager parentDpm = dpm.getParentProfileInstance(userInfo);
-                        if ((parentDpm.getKeyguardDisabledFeatures(admin, userInfo.id)
-                                & keyguardFeatures) != 0) {
-                            if (enforcedAdmin == null) {
-                                enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
-                            } else {
-                                return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
-                            }
-                        }
-                    }
-                }
-            }
+            return checkForLockSetting(context, userId, check);
         }
-        return enforcedAdmin;
     }
 
     public static EnforcedAdmin checkIfUninstallBlocked(Context context,
@@ -383,6 +349,11 @@
      *
      */
     public static EnforcedAdmin checkIfPasswordQualityIsSet(Context context, int userId) {
+        final LockSettingCheck check =
+                (DevicePolicyManager dpm, ComponentName admin, @UserIdInt int checkUser) ->
+                        dpm.getPasswordQuality(admin, checkUser)
+                                > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+
         final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
                 Context.DEVICE_POLICY_SERVICE);
         if (dpm == null) {
@@ -390,7 +361,6 @@
         }
 
         LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
-        EnforcedAdmin enforcedAdmin = null;
         if (lockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
             // userId is managed profile and has a separate challenge, only consider
             // the admins in that user.
@@ -398,9 +368,9 @@
             if (admins == null) {
                 return null;
             }
+            EnforcedAdmin enforcedAdmin = null;
             for (ComponentName admin : admins) {
-                if (dpm.getPasswordQuality(admin, userId)
-                        > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
+                if (check.isEnforcing(dpm, admin, userId)) {
                     if (enforcedAdmin == null) {
                         enforcedAdmin = new EnforcedAdmin(admin, userId);
                     } else {
@@ -408,50 +378,10 @@
                     }
                 }
             }
+            return enforcedAdmin;
         } else {
-            // Return all admins for this user and the profiles that are visible from this
-            // user that do not use a separate work challenge.
-            final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
-            for (UserInfo userInfo : um.getProfiles(userId)) {
-                final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userInfo.id);
-                if (admins == null) {
-                    continue;
-                }
-                final boolean isSeparateProfileChallengeEnabled =
-                        lockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id);
-                for (ComponentName admin : admins) {
-                    if (!isSeparateProfileChallengeEnabled) {
-                        if (dpm.getPasswordQuality(admin, userInfo.id)
-                                > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
-                            if (enforcedAdmin == null) {
-                                enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
-                            } else {
-                                return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
-                            }
-                            // This same admins could have set policies both on the managed profile
-                            // and on the parent. So, if the admin has set the policy on the
-                            // managed profile here, we don't need to further check if that admin
-                            // has set policy on the parent admin.
-                            continue;
-                        }
-                    }
-                    if (userInfo.isManagedProfile()) {
-                        // If userInfo.id is a managed profile, we also need to look at
-                        // the policies set on the parent.
-                        DevicePolicyManager parentDpm = dpm.getParentProfileInstance(userInfo);
-                        if (parentDpm.getPasswordQuality(admin, userInfo.id)
-                                > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
-                            if (enforcedAdmin == null) {
-                                enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
-                            } else {
-                                return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
-                            }
-                        }
-                    }
-                }
-            }
+            return checkForLockSetting(context, userId, check);
         }
-        return enforcedAdmin;
     }
 
     /**
@@ -512,6 +442,65 @@
         return enforcedAdmin;
     }
 
+    private interface LockSettingCheck {
+        boolean isEnforcing(DevicePolicyManager dpm, ComponentName admin, @UserIdInt int userId);
+    }
+
+    /**
+     * Checks whether any of the user's profiles enforce the lock setting. A managed profile is only
+     * included if it does not have a separate challenege but the settings for it's parent (i.e. the
+     * user being checked) are always included.
+     */
+    private static EnforcedAdmin checkForLockSetting(
+            Context context, @UserIdInt int userId, LockSettingCheck check) {
+        final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
+        if (dpm == null) {
+            return null;
+        }
+        final LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
+        EnforcedAdmin enforcedAdmin = null;
+        // Return all admins for this user and the profiles that are visible from this
+        // user that do not use a separate work challenge.
+        for (UserInfo userInfo : UserManager.get(context).getProfiles(userId)) {
+            final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userInfo.id);
+            if (admins == null) {
+                continue;
+            }
+            final boolean isSeparateProfileChallengeEnabled =
+                    lockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id);
+            for (ComponentName admin : admins) {
+                if (!isSeparateProfileChallengeEnabled) {
+                    if (check.isEnforcing(dpm, admin, userInfo.id)) {
+                        if (enforcedAdmin == null) {
+                            enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
+                        } else {
+                            return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
+                        }
+                        // This same admins could have set policies both on the managed profile
+                        // and on the parent. So, if the admin has set the policy on the
+                        // managed profile here, we don't need to further check if that admin
+                        // has set policy on the parent admin.
+                        continue;
+                    }
+                }
+                if (userInfo.isManagedProfile()) {
+                    // If userInfo.id is a managed profile, we also need to look at
+                    // the policies set on the parent.
+                    final DevicePolicyManager parentDpm = dpm.getParentProfileInstance(userInfo);
+                    if (check.isEnforcing(parentDpm, admin, userInfo.id)) {
+                        if (enforcedAdmin == null) {
+                            enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
+                        } else {
+                            return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
+                        }
+                    }
+                }
+            }
+        }
+        return enforcedAdmin;
+    }
+
     public static EnforcedAdmin getProfileOrDeviceOwner(Context context, int userId) {
         if (userId == UserHandle.USER_NULL) {
             return null;
diff --git a/packages/SettingsLib/src/com/android/settingslib/widget/AnimatedImageView.java b/packages/SettingsLib/src/com/android/settingslib/widget/AnimatedImageView.java
index f5e39be..a8cd655 100644
--- a/packages/SettingsLib/src/com/android/settingslib/widget/AnimatedImageView.java
+++ b/packages/SettingsLib/src/com/android/settingslib/widget/AnimatedImageView.java
@@ -55,7 +55,7 @@
 
     private void updateAnimating() {
         if (mDrawable != null) {
-            if (isShown() && mAnimating) {
+            if (getVisibility() == View.VISIBLE && mAnimating) {
                 mDrawable.start();
             } else {
                 mDrawable.stop();
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index c2161ae..e7450fa 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -288,7 +288,7 @@
 
     public boolean matches(WifiConfiguration config) {
         if (config.isPasspoint() && mConfig != null && mConfig.isPasspoint()) {
-            return config.FQDN.equals(mConfig.FQDN);
+            return ssid.equals(removeDoubleQuotes(config.SSID)) && config.FQDN.equals(mConfig.FQDN);
         } else {
             return ssid.equals(removeDoubleQuotes(config.SSID))
                     && security == getSecurity(config)
@@ -839,16 +839,19 @@
         if (state == DetailedState.CONNECTED) {
             IWifiManager wifiManager = IWifiManager.Stub.asInterface(
                     ServiceManager.getService(Context.WIFI_SERVICE));
-            Network nw;
+            NetworkCapabilities nc = null;
 
             try {
-                nw = wifiManager.getCurrentNetwork();
-            } catch (RemoteException e) {
-                nw = null;
-            }
-            NetworkCapabilities nc = cm.getNetworkCapabilities(nw);
-            if (nc != null && !nc.hasCapability(nc.NET_CAPABILITY_VALIDATED)) {
-                return context.getString(R.string.wifi_connected_no_internet);
+                nc = cm.getNetworkCapabilities(wifiManager.getCurrentNetwork());
+            } catch (RemoteException e) {}
+
+            if (nc != null) {
+                if (nc.hasCapability(nc.NET_CAPABILITY_CAPTIVE_PORTAL)) {
+                    return context.getString(
+                        com.android.internal.R.string.network_available_sign_in);
+                } else if (!nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
+                    return context.getString(R.string.wifi_connected_no_internet);
+                }
             }
         }
         if (state == null) {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
new file mode 100644
index 0000000..025bbc2
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.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.settingslib;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.UserManager;
+
+import com.android.internal.util.ArrayUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import java.util.Arrays;
+
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT;
+import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.when;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class RestrictedLockUtilsTest {
+
+    @Mock
+    private Context mContext;
+    @Mock
+    private DevicePolicyManager mDevicePolicyManager;
+    @Mock
+    private UserManager mUserManager;
+
+    private static final int mUserId = 194;
+    private static final ComponentName mAdmin1 = new ComponentName("admin1", "admin1class");
+    private static final ComponentName mAdmin2 = new ComponentName("admin2", "admin2class");
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE))
+                .thenReturn(mDevicePolicyManager);
+        when(mContext.getSystemService(Context.USER_SERVICE))
+                .thenReturn(mUserManager);
+    }
+
+    @Test
+    public void checkIfKeyguardFeaturesDisabled_noEnforcedAdminForManagedProfile() {
+        setUpManagedProfile(mUserId);
+        setUpActiveAdmins(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
+
+        final EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+                mContext, KEYGUARD_DISABLE_FINGERPRINT, mUserId);
+
+        assertThat(enforcedAdmin).isEqualTo(null);
+    }
+
+    @Test
+    public void checkIfKeyguardFeaturesDisabled_oneEnforcedAdminForManagedProfile() {
+        setUpManagedProfile(mUserId);
+        setUpActiveAdmins(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
+
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin1, mUserId))
+                .thenReturn(KEYGUARD_DISABLE_FINGERPRINT);
+
+        final EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+                mContext, KEYGUARD_DISABLE_FINGERPRINT, mUserId);
+
+        assertThat(enforcedAdmin).isEqualTo(new EnforcedAdmin(mAdmin1, mUserId));
+    }
+
+    @Test
+    public void checkIfKeyguardFeaturesDisabled_multipleEnforcedAdminForManagedProfile() {
+        setUpManagedProfile(mUserId);
+        setUpActiveAdmins(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
+
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin1, mUserId))
+                .thenReturn(KEYGUARD_DISABLE_REMOTE_INPUT);
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin2, mUserId))
+                .thenReturn(KEYGUARD_DISABLE_REMOTE_INPUT);
+
+        final EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+                mContext, KEYGUARD_DISABLE_REMOTE_INPUT, mUserId);
+
+        assertThat(enforcedAdmin).isEqualTo(EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN);
+    }
+
+    private UserInfo setUpManagedProfile(int userId) {
+        final UserInfo userInfo = new UserInfo(userId, "myuser", UserInfo.FLAG_MANAGED_PROFILE);
+        when(mUserManager.getUserInfo(userId)).thenReturn(userInfo);
+        return userInfo;
+    }
+
+    private void setUpActiveAdmins(int userId, ComponentName[] activeAdmins) {
+        when(mDevicePolicyManager.getActiveAdminsAsUser(userId))
+                .thenReturn(Arrays.asList(activeAdmins));
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.java
new file mode 100644
index 0000000..2c9c868
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.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 com.android.settingslib.widget;
+
+import android.app.Activity;
+import android.graphics.drawable.AnimatedRotateDrawable;
+import android.view.View;
+import com.android.settingslib.TestConfig;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class AnimatedImageViewTest {
+    private AnimatedImageView mAnimatedImageView;
+
+    @Before
+    public void setUp() {
+        Activity activity = Robolectric.setupActivity(Activity.class);
+        mAnimatedImageView = new AnimatedImageView(activity);
+        mAnimatedImageView.setImageDrawable(new AnimatedRotateDrawable());
+    }
+
+    @Test
+    public void testAnimation_ViewVisible_AnimationRunning() {
+        mAnimatedImageView.setVisibility(View.VISIBLE);
+        mAnimatedImageView.setAnimating(true);
+        AnimatedRotateDrawable drawable = (AnimatedRotateDrawable) mAnimatedImageView.getDrawable();
+        assertThat(drawable.isRunning()).isTrue();
+    }
+
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 88ee33c..c149876 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -57,6 +57,7 @@
 import android.os.UserManager;
 import android.os.UserManagerInternal;
 import android.provider.Settings;
+import android.provider.Settings.Global;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -2175,7 +2176,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 135;
+            private static final int SETTINGS_VERSION = 136;
 
             private final int mUserId;
 
@@ -2553,6 +2554,30 @@
                     currentVersion = 135;
                 }
 
+                if (currentVersion == 135) {
+                    // Version 135: Migrating the NETWORK_SCORER_APP setting to the
+                    // NETWORK_RECOMMENDATIONS_ENABLED setting.
+                    if (userId == UserHandle.USER_SYSTEM) {
+                        final SettingsState globalSettings = getGlobalSettingsLocked();
+                        Setting currentSetting = globalSettings.getSettingLocked(
+                            Global.NETWORK_SCORER_APP);
+                        if (!currentSetting.isNull()) {
+                            // A scorer was set so enable recommendations.
+                            globalSettings.insertSettingLocked(
+                                Global.NETWORK_RECOMMENDATIONS_ENABLED,
+                                "1",
+                                SettingsState.SYSTEM_PACKAGE_NAME);
+
+                            // and clear the scorer setting since it's no longer needed.
+                            globalSettings.insertSettingLocked(
+                                Global.NETWORK_SCORER_APP,
+                                null,
+                                SettingsState.SYSTEM_PACKAGE_NAME);
+                        }
+                    }
+                    currentVersion = 136;
+                }
+
                 if (currentVersion != newVersion) {
                     Slog.wtf("SettingsProvider", "warning: upgrading settings database to version "
                             + newVersion + " left it at "
diff --git a/packages/SystemUI/res/color/qs_detail_empty.xml b/packages/SystemUI/res/color/qs_detail_empty.xml
deleted file mode 100644
index 4be39c7..0000000
--- a/packages/SystemUI/res/color/qs_detail_empty.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:alpha="0.14" android:color="@*android:color/quaternary_device_default_settings" />
-</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-xhdpi/ic_sysbar_back.png
new file mode 100644
index 0000000..94cb032
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-sw900dp-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back.png
new file mode 100644
index 0000000..fbdc93c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back_ime.png
new file mode 100644
index 0000000..419518c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_home.png
new file mode 100644
index 0000000..a2406b1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_menu.png
new file mode 100644
index 0000000..50043eb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_recent.png
new file mode 100644
index 0000000..c449449
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp/ic_ime_switcher_default.xml b/packages/SystemUI/res/drawable-sw900dp/ic_ime_switcher_default.xml
new file mode 100644
index 0000000..bcf9cac
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp/ic_ime_switcher_default.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="28.0dp"
+    android:height="28.0dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:pathData="M20.000000,5.000000L4.000000,5.000000C2.900000,5.000000 2.000000,5.900000 2.000000,7.000000l0.000000,10.000000c0.000000,1.100000 0.900000,2.000000 2.000000,2.000000l16.000000,0.000000c1.100000,0.000000 2.000000,-0.900000 2.000000,-2.000000L22.000000,7.000000C22.000000,5.900000 21.100000,5.000000 20.000000,5.000000zM11.000000,8.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000L11.000000,8.000000zM11.000000,11.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000L11.000000,11.000000zM8.000000,8.000000l2.000000,0.000000l0.000000,2.000000L8.000000,10.000000L8.000000,8.000000zM8.000000,11.000000l2.000000,0.000000l0.000000,2.000000L8.000000,13.000000L8.000000,11.000000zM7.000000,13.000000L5.000000,13.000000l0.000000,-2.000000l2.000000,0.000000L7.000000,13.000000zM7.000000,10.000000L5.000000,10.000000L5.000000,8.000000l2.000000,0.000000L7.000000,10.000000zM16.000000,17.000000L8.000000,17.000000l0.000000,-2.000000l8.000000,0.000000L16.000000,17.000000zM16.000000,13.000000l-2.000000,0.000000l0.000000,-2.000000l2.000000,0.000000L16.000000,13.000000zM16.000000,10.000000l-2.000000,0.000000L14.000000,8.000000l2.000000,0.000000L16.000000,10.000000zM19.000000,13.000000l-2.000000,0.000000l0.000000,-2.000000l2.000000,0.000000L19.000000,13.000000zM19.000000,10.000000l-2.000000,0.000000L17.000000,8.000000l2.000000,0.000000L19.000000,10.000000z"
+        android:fillColor="@color/navigation_bar_icon_color"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_mode_edit.xml b/packages/SystemUI/res/drawable/ic_mode_edit.xml
index 8a73686..f32da59 100644
--- a/packages/SystemUI/res/drawable/ic_mode_edit.xml
+++ b/packages/SystemUI/res/drawable/ic_mode_edit.xml
@@ -17,7 +17,8 @@
         android:width="20.0dp"
         android:height="20.0dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
+        android:viewportHeight="24.0"
+        android:tint="?android:attr/colorControlNormal">
     <path
         android:fillColor="#FFFFFF"
         android:pathData="M3.0,17.25L3.0,21.0l3.75,0.0L17.81,9.94l-3.75,-3.75L3.0,17.25zM20.71,7.04c0.39,-0.3 0.39,-1.02 0.0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0.0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth_detail_empty.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_detail_empty.xml
index 435bb9b..33a4047 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth_detail_empty.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_detail_empty.xml
@@ -18,9 +18,10 @@
         android:height="56dp"
         android:viewportWidth="48.0"
         android:viewportHeight="48.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:alpha="0.14"
+        android:tint="?android:attr/colorForeground">
 
     <path
-        android:fillColor="@color/qs_detail_empty"
+        android:fillColor="#FFFFFF"
         android:pathData="M35.4,15.4L24.0,4.0l-2.0,0.0l0.0,15.2L12.8,10.0L10.0,12.8L21.2,24.0L10.0,35.2l2.8,2.8l9.2,-9.2L22.0,44.0l2.0,0.0l11.4,-11.4L26.8,24.0L35.4,15.4zM26.0,11.7l3.8,3.8L26.0,19.2L26.0,11.7zM29.8,32.6L26.0,36.3l0.0,-7.5L29.8,32.6z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_cast_detail_empty.xml b/packages/SystemUI/res/drawable/ic_qs_cast_detail_empty.xml
index 59dcea2..fc831f4 100644
--- a/packages/SystemUI/res/drawable/ic_qs_cast_detail_empty.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_cast_detail_empty.xml
@@ -17,9 +17,11 @@
         android:width="56dp"
         android:height="56dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
+        android:viewportHeight="48.0"
+        android:alpha="0.14"
+        android:tint="?android:attr/colorForeground">
 
     <path
-        android:fillColor="@color/qs_detail_empty"
+        android:fillColor="#FFFFFF"
         android:pathData="M42.0,6.0L6.0,6.0c-2.2,0.0 -4.0,1.8 -4.0,4.0l0.0,6.0l4.0,0.0l0.0,-6.0l36.0,0.0l0.0,28.0L28.0,38.0l0.0,4.0l14.0,0.0c2.2,0.0 4.0,-1.8 4.0,-4.0L46.0,10.0C46.0,7.8 44.2,6.0 42.0,6.0zM2.0,36.0l0.0,6.0l6.0,0.0C8.0,38.7 5.3,36.0 2.0,36.0zM2.0,28.0l0.0,4.0c5.5,0.0 10.0,4.5 10.0,10.0l4.0,0.0C16.0,34.3 9.7,28.0 2.0,28.0zM2.0,20.0l0.0,4.0c9.9,0.0 18.0,8.1 18.0,18.0l4.0,0.0C24.0,29.8 14.1,20.0 2.0,20.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_minus.xml b/packages/SystemUI/res/drawable/ic_qs_minus.xml
index 6a3410a..147a94b 100644
--- a/packages/SystemUI/res/drawable/ic_qs_minus.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_minus.xml
@@ -17,7 +17,8 @@
     android:height="24.0dp"
     android:viewportHeight="48.0"
     android:viewportWidth="48.0"
-    android:width="24.0dp" >
+    android:width="24.0dp"
+    android:tint="?android:attr/colorControlNormal" >
 
     <path
         android:fillColor="#FFFFFFFF"
diff --git a/packages/SystemUI/res/drawable/ic_qs_plus.xml b/packages/SystemUI/res/drawable/ic_qs_plus.xml
index 393f51c..1f254d1 100644
--- a/packages/SystemUI/res/drawable/ic_qs_plus.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_plus.xml
@@ -17,7 +17,8 @@
     android:height="24.0dp"
     android:viewportHeight="48.0"
     android:viewportWidth="48.0"
-    android:width="24.0dp" >
+    android:width="24.0dp"
+    android:tint="?android:attr/colorControlNormal" >
 
     <path
         android:fillColor="#FFFFFFFF"
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_detail_empty.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_detail_empty.xml
index a7889ab..7993c80 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_detail_empty.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_detail_empty.xml
@@ -18,9 +18,10 @@
         android:height="56dp"
         android:viewportWidth="48.0"
         android:viewportHeight="48.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:alpha="0.14"
+        android:tint="?android:attr/colorForeground">
 
     <path
         android:pathData="M24.0,4.0C15.0,4.0 6.7,7.0 0.0,12.0l24.0,32.0l24.0,-32.0C41.3,7.0 33.0,4.0 24.0,4.0z"
-        android:fillColor="@color/qs_detail_empty" />
+        android:fillColor="#FFFFFF" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_settings_20dp.xml b/packages/SystemUI/res/drawable/ic_settings_20dp.xml
index 3170f86..45ee94f 100644
--- a/packages/SystemUI/res/drawable/ic_settings_20dp.xml
+++ b/packages/SystemUI/res/drawable/ic_settings_20dp.xml
@@ -17,7 +17,8 @@
     android:width="20dp"
     android:height="20dp"
     android:viewportWidth="24.0"
-    android:viewportHeight="24.0">
+    android:viewportHeight="24.0"
+    android:tint="?android:attr/colorControlNormal">
     <path
         android:pathData="M19.4,13.0c0.0,-0.3 0.1,-0.6 0.1,-1.0s0.0,-0.7 -0.1,-1.0l2.1,-1.7c0.2,-0.2 0.2,-0.4 0.1,-0.6l-2.0,-3.5C19.5,5.1 19.3,5.0 19.0,5.1l-2.5,1.0c-0.5,-0.4 -1.1,-0.7 -1.7,-1.0l-0.4,-2.6C14.5,2.2 14.2,2.0 14.0,2.0l-4.0,0.0C9.8,2.0 9.5,2.2 9.5,2.4L9.1,5.1C8.5,5.3 8.0,5.7 7.4,6.1L5.0,5.1C4.7,5.0 4.5,5.1 4.3,5.3l-2.0,3.5C2.2,8.9 2.3,9.2 2.5,9.4L4.6,11.0c0.0,0.3 -0.1,0.6 -0.1,1.0s0.0,0.7 0.1,1.0l-2.1,1.7c-0.2,0.2 -0.2,0.4 -0.1,0.6l2.0,3.5C4.5,18.9 4.7,19.0 5.0,18.9l2.5,-1.0c0.5,0.4 1.1,0.7 1.7,1.0l0.4,2.6c0.0,0.2 0.2,0.4 0.5,0.4l4.0,0.0c0.2,0.0 0.5,-0.2 0.5,-0.4l0.4,-2.6c0.6,-0.3 1.2,-0.6 1.7,-1.0l2.5,1.0c0.2,0.1 0.5,0.0 0.6,-0.2l2.0,-3.5c0.1,-0.2 0.1,-0.5 -0.1,-0.6L19.4,13.0zM12.0,15.5c-1.9,0.0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5s3.5,1.6 3.5,3.5S13.9,15.5 12.0,15.5z"
         android:fillColor="#ffffffff" />
diff --git a/packages/SystemUI/res/drawable/major_a_b.xml b/packages/SystemUI/res/drawable/major_a_b.xml
index 9900048..45386f9 100644
--- a/packages/SystemUI/res/drawable/major_a_b.xml
+++ b/packages/SystemUI/res/drawable/major_a_b.xml
@@ -20,7 +20,8 @@
     android:width="16dp"
     android:viewportWidth="16"
     android:height="8dp"
-    android:viewportHeight="8" >
+    android:viewportHeight="8"
+    android:tint="?android:attr/colorControlNormal">
     <group
         android:name="dot_01"
         android:translateX="3.25"
diff --git a/packages/SystemUI/res/drawable/major_b_a.xml b/packages/SystemUI/res/drawable/major_b_a.xml
index 3115887..4fcff0c 100644
--- a/packages/SystemUI/res/drawable/major_b_a.xml
+++ b/packages/SystemUI/res/drawable/major_b_a.xml
@@ -20,7 +20,8 @@
     android:width="16dp"
     android:viewportWidth="16"
     android:height="8dp"
-    android:viewportHeight="8" >
+    android:viewportHeight="8"
+    android:tint="?android:attr/colorControlNormal" >
     <group
         android:name="dot_01"
         android:translateX="8"
diff --git a/packages/SystemUI/res/drawable/major_b_c.xml b/packages/SystemUI/res/drawable/major_b_c.xml
index 899109e..c03a8d5 100644
--- a/packages/SystemUI/res/drawable/major_b_c.xml
+++ b/packages/SystemUI/res/drawable/major_b_c.xml
@@ -20,7 +20,8 @@
     android:width="16dp"
     android:viewportWidth="16"
     android:height="8dp"
-    android:viewportHeight="8" >
+    android:viewportHeight="8"
+    android:tint="?android:attr/colorControlNormal" >
     <group
         android:name="dot_01"
         android:translateX="8"
diff --git a/packages/SystemUI/res/drawable/major_c_b.xml b/packages/SystemUI/res/drawable/major_c_b.xml
index cc6c615..9e4e245 100644
--- a/packages/SystemUI/res/drawable/major_c_b.xml
+++ b/packages/SystemUI/res/drawable/major_c_b.xml
@@ -20,7 +20,8 @@
     android:width="16dp"
     android:viewportWidth="16"
     android:height="8dp"
-    android:viewportHeight="8" >
+    android:viewportHeight="8"
+    android:tint="?android:attr/colorControlNormal" >
     <group
         android:name="dot_01"
         android:translateX="12.75"
diff --git a/packages/SystemUI/res/drawable/minor_a_b.xml b/packages/SystemUI/res/drawable/minor_a_b.xml
index c5f5c98..0622aac 100644
--- a/packages/SystemUI/res/drawable/minor_a_b.xml
+++ b/packages/SystemUI/res/drawable/minor_a_b.xml
@@ -21,7 +21,8 @@
     android:width="16dp"
     android:viewportWidth="16"
     android:height="8dp"
-    android:viewportHeight="8" >
+    android:viewportHeight="8"
+    android:tint="?android:attr/colorControlNormal" >
     <group
         android:name="dot_02"
         android:translateX="3.25"
diff --git a/packages/SystemUI/res/drawable/minor_b_a.xml b/packages/SystemUI/res/drawable/minor_b_a.xml
index 3bb08c4..ecb4341 100644
--- a/packages/SystemUI/res/drawable/minor_b_a.xml
+++ b/packages/SystemUI/res/drawable/minor_b_a.xml
@@ -21,7 +21,8 @@
     android:width="16dp"
     android:viewportWidth="16"
     android:height="8dp"
-    android:viewportHeight="8" >
+    android:viewportHeight="8"
+    android:tint="?android:attr/colorControlNormal" >
     <group
         android:name="dot_02"
         android:translateX="8"
diff --git a/packages/SystemUI/res/drawable/minor_b_c.xml b/packages/SystemUI/res/drawable/minor_b_c.xml
index 95c6463..7f59e34 100644
--- a/packages/SystemUI/res/drawable/minor_b_c.xml
+++ b/packages/SystemUI/res/drawable/minor_b_c.xml
@@ -21,7 +21,8 @@
     android:width="16dp"
     android:viewportWidth="16"
     android:height="8dp"
-    android:viewportHeight="8" >
+    android:viewportHeight="8"
+    android:tint="?android:attr/colorControlNormal" >
     <group
         android:name="dot_02"
         android:translateX="8"
diff --git a/packages/SystemUI/res/drawable/minor_c_b.xml b/packages/SystemUI/res/drawable/minor_c_b.xml
index 523afaa..97309bc 100644
--- a/packages/SystemUI/res/drawable/minor_c_b.xml
+++ b/packages/SystemUI/res/drawable/minor_c_b.xml
@@ -21,7 +21,8 @@
     android:width="16dp"
     android:viewportWidth="16"
     android:height="8dp"
-    android:viewportHeight="8" >
+    android:viewportHeight="8"
+    android:tint="?android:attr/colorControlNormal" >
     <group
         android:name="dot_02"
         android:translateX="12.75"
diff --git a/packages/SystemUI/res/layout/pip_menu_action.xml b/packages/SystemUI/res/layout/pip_menu_action.xml
new file mode 100644
index 0000000..db6ae19
--- /dev/null
+++ b/packages/SystemUI/res/layout/pip_menu_action.xml
@@ -0,0 +1,44 @@
+<?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.
+-->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="0dp"
+    android:layout_height="match_parent"
+    android:layout_weight="1"
+    android:background="?android:selectableItemBackground">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:orientation="vertical">
+        <ImageView
+            android:id="@+id/icon"
+            android:layout_width="@dimen/pip_menu_action_icon_size"
+            android:layout_height="@dimen/pip_menu_action_icon_size"
+            android:layout_gravity="center_horizontal"
+            android:layout_marginBottom="4dp" />
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:includeFontPadding="false"
+            android:gravity="center"
+            android:textSize="12sp"
+            android:textColor="#ffffffff"
+            android:textAllCaps="true"
+            android:fontFamily="sans-serif" />
+    </LinearLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/pip_menu_activity.xml b/packages/SystemUI/res/layout/pip_menu_activity.xml
index 88e6e72..054bfab 100644
--- a/packages/SystemUI/res/layout/pip_menu_activity.xml
+++ b/packages/SystemUI/res/layout/pip_menu_activity.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 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.
@@ -16,21 +16,44 @@
 
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/menu"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="#33000000">
+
     <LinearLayout
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center">
-        <Button
-            android:id="@+id/expand_pip"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center"
-            android:textSize="14sp"
+        android:id="@+id/actions"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginBottom="48dp">
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="48dp"
+        android:layout_gravity="bottom"
+        android:orientation="horizontal">
+        <TextView
+            android:id="@+id/dismiss"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center"
+            android:textSize="12sp"
             android:textColor="#ffffffff"
-            android:text="@string/pip_phone_expand"
-            android:fontFamily="sans-serif" />
+            android:fontFamily="sans-serif"
+            android:text="@string/pip_phone_dismiss"
+            android:background="?android:selectableItemBackground" />
+        <TextView
+            android:id="@+id/minimize"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center"
+            android:textSize="12sp"
+            android:textColor="#ffffffff"
+            android:fontFamily="sans-serif"
+            android:text="@string/pip_phone_minimize"
+            android:background="?android:selectableItemBackground" />
     </LinearLayout>
 </FrameLayout>
diff --git a/packages/SystemUI/res/layout/recents_grid_task_view.xml b/packages/SystemUI/res/layout/recents_grid_task_view.xml
new file mode 100644
index 0000000..53bec70
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_grid_task_view.xml
@@ -0,0 +1,35 @@
+<?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.recents.views.grid.GridTaskView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:focusable="true">
+    <com.android.systemui.recents.views.TaskViewThumbnail
+        android:id="@+id/task_view_thumbnail"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+    <include layout="@layout/recents_task_view_header" />
+
+    <!-- TODO: Move this into a view stub -->
+    <include layout="@layout/recents_task_view_lock_to_app"/>
+
+    <!-- The incompatible app toast -->
+    <include layout="@layout/recents_task_view_incompatible_app_toast"/>
+</com.android.systemui.recents.views.grid.GridTaskView>
+
+
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index c8e5b61..015e4a2 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -4,9 +4,9 @@
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at
-  
+
           http://www.apache.org/licenses/LICENSE-2.0
-  
+
      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -26,35 +26,10 @@
     <include layout="@layout/recents_task_view_header" />
 
     <!-- TODO: Move this into a view stub -->
-    <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
-        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|end"
-        android:layout_marginEnd="15dp"
-        android:layout_marginBottom="15dp"
-        android:translationZ="4dp"
-        android:contentDescription="@string/recents_lock_to_app_button_label"
-        android:background="@drawable/recents_lock_to_task_button_bg"
-        android:visibility="invisible"
-        android:alpha="0">
-        <ImageView
-            android:layout_width="@dimen/recents_lock_to_app_icon_size"
-            android:layout_height="@dimen/recents_lock_to_app_icon_size"
-            android:layout_gravity="center"
-            android:src="@drawable/recents_lock_to_app_pin" />
-    </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
+    <include layout="@layout/recents_task_view_lock_to_app"/>
 
     <!-- The incompatible app toast -->
-    <ViewStub android:id="@+id/incompatible_app_toast_stub"
-                android:inflatedId="@+id/incompatible_app_toast"
-                android:layout="@*android:layout/transient_notification"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="top|center_horizontal"
-                android:layout_marginTop="48dp"
-                android:layout_marginLeft="16dp"
-                android:layout_marginRight="16dp" />
+    <include layout="@layout/recents_task_view_incompatible_app_toast"/>
 </com.android.systemui.recents.views.TaskView>
 
 
diff --git a/packages/SystemUI/res/layout/recents_task_view_incompatible_app_toast.xml b/packages/SystemUI/res/layout/recents_task_view_incompatible_app_toast.xml
new file mode 100644
index 0000000..d573d6b
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_task_view_incompatible_app_toast.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.
+-->
+<ViewStub
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/incompatible_app_toast_stub"
+    android:inflatedId="@+id/incompatible_app_toast"
+    android:layout="@*android:layout/transient_notification"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="top|center_horizontal"
+    android:layout_marginTop="48dp"
+    android:layout_marginLeft="16dp"
+    android:layout_marginRight="16dp" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_task_view_lock_to_app.xml b/packages/SystemUI/res/layout/recents_task_view_lock_to_app.xml
new file mode 100644
index 0000000..8cece11
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_task_view_lock_to_app.xml
@@ -0,0 +1,34 @@
+<?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.AlphaOptimizedFrameLayout
+  xmlns:android="http://schemas.android.com/apk/res/android"
+    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|end"
+    android:layout_marginEnd="15dp"
+    android:layout_marginBottom="15dp"
+    android:translationZ="4dp"
+    android:contentDescription="@string/recents_lock_to_app_button_label"
+    android:background="@drawable/recents_lock_to_task_button_bg"
+    android:visibility="invisible"
+    android:alpha="0">
+    <ImageView
+        android:layout_width="@dimen/recents_lock_to_app_icon_size"
+        android:layout_height="@dimen/recents_lock_to_app_icon_size"
+        android:layout_gravity="center"
+        android:src="@drawable/recents_lock_to_app_pin" />
+</com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-sw900dp/config.xml b/packages/SystemUI/res/values-sw900dp/config.xml
new file mode 100644
index 0000000..182fa36
--- /dev/null
+++ b/packages/SystemUI/res/values-sw900dp/config.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.
+*/
+-->
+<resources>
+
+    <!-- Nav bar button default ordering/layout -->
+    <string name="config_navBarLayout" translatable="false">space[.2],back,home;space;menu_ime,recent,space[.2]</string>
+
+</resources>
diff --git a/packages/SystemUI/res/values-sw900dp/dimens.xml b/packages/SystemUI/res/values-sw900dp/dimens.xml
new file mode 100644
index 0000000..72e10c2
--- /dev/null
+++ b/packages/SystemUI/res/values-sw900dp/dimens.xml
@@ -0,0 +1,40 @@
+<?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>
+
+    <!-- All ryu nav buttons are th same size -->
+    <dimen name="button_size">80dp</dimen>
+    <dimen name="navigation_side_padding">@dimen/button_size</dimen>
+    <dimen name="navigation_key_width">@dimen/button_size</dimen>
+    <dimen name="navigation_extra_key_width">@dimen/button_size</dimen>
+
+    <!-- The maximum width of the navigation bar ripples. -->
+    <dimen name="key_button_ripple_max_width">76dp</dimen>
+
+    <!-- The padding around the navigation buttons -->
+    <dimen name="navigation_key_padding">5dp</dimen>
+
+    <!-- The inner radius of the halo. -->
+    <dimen name="halo_inner_radius">12dp</dimen>
+
+    <!-- The thickness of the halo. -->
+    <dimen name="halo_thickness">1dp</dimen>
+
+    <!-- The diameter of the halo. This is 2*(halo_inner_radius + halo_thickness). -->
+    <dimen name="halo_diameter">26dp</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a7d4aa0..fe5606e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -717,6 +717,9 @@
     <!-- The size of the PIP dismiss target. -->
     <dimen name="pip_dismiss_target_size">48dp</dimen>
 
+    <!-- The size of a PIP menu action icon. -->
+    <dimen name="pip_menu_action_icon_size">32dp</dimen>
+
     <!-- Values specific to grid-based recents. -->
     <!-- Margins around recent tasks. -->
     <dimen name="recents_grid_margin_left">15dp</dimen>
diff --git a/packages/SystemUI/res/values/dimens_grid.xml b/packages/SystemUI/res/values/dimens_grid.xml
new file mode 100644
index 0000000..43e152a
--- /dev/null
+++ b/packages/SystemUI/res/values/dimens_grid.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>
+  <dimen name="recents_grid_padding_left_right">32dp</dimen>
+  <dimen name="recents_grid_padding_top_bottom">84dp</dimen>
+  <dimen name="recents_grid_padding_task_view">20dp</dimen>
+</resources>
+
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index c8b3b69d..31b83cc 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1121,19 +1121,18 @@
     <!-- Toast shown when user unlocks screen and managed profile activity is in the foreground -->
     <string name="managed_profile_foreground_toast">You\'re using your work profile</string>
 
-    <string-array name="volume_stream_titles">
-        <item>Call</item> <!-- STREAM_VOICE_CALL -->
-        <item>System</item> <!-- STREAM_SYSTEM -->
-        <item>Ring</item> <!-- STREAM_RING -->
-        <item>Media</item> <!-- STREAM_MUSIC -->
-        <item>Alarm</item> <!-- STREAM_ALARM -->
-        <item></item> <!-- STREAM_NOTIFICATION -->
-        <item>Bluetooth</item> <!-- STREAM_BLUETOOTH_SCO -->
-        <item></item> <!-- STREAM_SYSTEM_ENFORCED -->
-        <item></item> <!-- STREAM_DTMF -->
-        <item></item> <!-- STREAM_TTS -->
-        <item>Accessibility</item> <!-- STREAM_ACCESSIBILITY -->
-    </string-array>
+    <!-- volume stream names. All nouns. -->
+    <string name="stream_voice_call">Call</string> <!-- STREAM_VOICE_CALL -->
+    <string name="stream_system">System</string> <!-- STREAM_SYSTEM -->
+    <string name="stream_ring">Ring</string> <!-- STREAM_RING -->
+    <string name="stream_music">Media</string> <!-- STREAM_MUSIC -->
+    <string name="stream_alarm">Alarm</string> <!-- STREAM_ALARM -->
+    <string name="stream_notification">Notification</string> <!-- STREAM_NOTIFICATION -->
+    <string name="stream_bluetooth_sco">Bluetooth</string> <!-- STREAM_BLUETOOTH_SCO -->
+    <string name="stream_system_enforced">System enforced</string> <!-- STREAM_SYSTEM_ENFORCED -->
+    <string name="stream_dtmf">Dual multi tone frequency</string> <!-- STREAM_DTMF -->
+    <string name="stream_tts">Text to speech</string> <!-- STREAM_TTS -->
+    <string name="stream_accessibility">Accessibility</string> <!-- STREAM_ACCESSIBILITY -->
 
     <string name="volume_stream_muted" translatable="false">%s silent</string>
     <string name="volume_stream_vibrate" translatable="false">%s vibrate</string>
@@ -1688,9 +1687,15 @@
         not appear on production builds ever. -->
     <string name="tuner_doze_always_on" translatable="false">Always on</string>
 
-    <!-- Making the PIP fullscreen -->
+    <!-- Making the PIP fullscreen [CHAR LIMIT=25] -->
     <string name="pip_phone_expand">Expand</string>
 
+    <!-- Label for PIP action to Minimize the PIP [CHAR LIMIT=25] -->
+    <string name="pip_phone_minimize">Minimize</string>
+
+    <!-- Label for PIP action to Dismiss the PIP -->
+    <string name="pip_phone_dismiss">Dismiss</string>
+
     <!-- PIP section of the tuner. Non-translatable since it should
         not appear on production builds ever. -->
     <string name="picture_in_picture" translatable="false">Picture-in-Picture</string>
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 9eceeac..2576bb7 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -13,6 +13,7 @@
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
 import android.os.AsyncTask;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -31,6 +32,7 @@
 import com.android.internal.app.AssistUtils;
 import com.android.internal.app.IVoiceInteractionSessionListener;
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.CommandQueue;
@@ -155,6 +157,7 @@
                         | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
                         | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                 PixelFormat.TRANSLUCENT);
+        lp.token = new Binder();
         if (ActivityManager.isHighEndGfx()) {
             lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
         }
@@ -282,7 +285,7 @@
 
     @Nullable
     private ComponentName getAssistInfo() {
-        return mAssistUtils.getAssistComponentForUser(UserHandle.USER_CURRENT);
+        return mAssistUtils.getAssistComponentForUser(KeyguardUpdateMonitor.getCurrentUser());
     }
 
     public void showDisclosure() {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingLog.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingLog.java
index 1338d9d..71ddba5 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingLog.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingLog.java
@@ -84,6 +84,11 @@
         log("I", tag, s);
     }
 
+    public static void wLogcat(String tag, String s) {
+        Log.w(TAG, tag + "\t" + s);
+        log("W", tag, s);
+    }
+
     public static void w(String tag, String s) {
         if (LOGCAT) {
             Log.w(TAG, tag + "\t" + s);
@@ -133,7 +138,7 @@
         pw.println();
     }
 
-    public static synchronized void wtf(String tag, String s) {
+    public static synchronized void wtf(String tag, String s, Throwable here) {
         if (!ENABLED) {
             return;
         }
@@ -161,6 +166,6 @@
             Log.e(TAG, "Unable to write log, build must be debuggable.");
         }
 
-        Log.wtf(TAG, tag + " " + s + "; " + fileMessage);
+        Log.wtf(TAG, tag + " " + s + "; " + fileMessage, here);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index 8fc555f..1abea37 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -71,6 +71,7 @@
     private boolean mSessionActive = false;
     private int mState = StatusBarState.SHADE;
     private boolean mScreenOn;
+    private Runnable mPendingWtf;
 
     protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
         @Override
@@ -136,6 +137,7 @@
     private void onSessionStart() {
         if (FalsingLog.ENABLED) {
             FalsingLog.i("onSessionStart", "classifierEnabled=" + isClassiferEnabled());
+            clearPendingWtf();
         }
         mBouncerOn = false;
         mSessionActive = true;
@@ -172,13 +174,35 @@
         if (FalsingLog.ENABLED) {
             // We're getting some false wtfs from touches that happen after the device went
             // to sleep. Only report missing sessions that happen when the device is interactive.
-            if (!mSessionActive && mContext.getSystemService(PowerManager.class).isInteractive()) {
-                FalsingLog.wtf("isFalseTouch", new StringBuilder()
+            if (!mSessionActive && mContext.getSystemService(PowerManager.class).isInteractive()
+                    && mPendingWtf == null) {
+                int enabled = isEnabled() ? 1 : 0;
+                int screenOn = mScreenOn ? 1 : 0;
+                String state = StatusBarState.toShortString(mState);
+                Throwable here = new Throwable("here");
+                FalsingLog.wLogcat("isFalseTouch", new StringBuilder()
                         .append("Session is not active, yet there's a query for a false touch.")
-                        .append(" enabled=").append(isEnabled() ? 1 : 0)
-                        .append(" mScreenOn=").append(mScreenOn ? 1 : 0)
-                        .append(" mState=").append(StatusBarState.toShortString(mState))
+                        .append(" enabled=").append(enabled)
+                        .append(" mScreenOn=").append(screenOn)
+                        .append(" mState=").append(state)
+                        .append(". Escalating to WTF if screen does not turn on soon.")
                         .toString());
+
+                // Unfortunately we're also getting false positives for touches that happen right
+                // after the screen turns on, but before that notification has made it to us.
+                // Unfortunately there's no good way to catch that, except to wait and see if we get
+                // the screen on notification soon.
+                mPendingWtf = () -> FalsingLog.wtf("isFalseTouch", new StringBuilder()
+                        .append("Session did not become active after query for a false touch.")
+                        .append(" enabled=").append(enabled)
+                        .append('/').append(isEnabled() ? 1 : 0)
+                        .append(" mScreenOn=").append(screenOn)
+                        .append('/').append(mScreenOn ? 1 : 0)
+                        .append(" mState=").append(state)
+                        .append('/').append(StatusBarState.toShortString(mState))
+                        .append(". Look for warnings ~1000ms earlier to see root cause.")
+                        .toString(), here);
+                mHandler.postDelayed(mPendingWtf, 1000);
             }
         }
         if (mAccessibilityManager.isTouchExplorationEnabled()) {
@@ -189,6 +213,13 @@
         return mHumanInteractionClassifier.isFalseTouch();
     }
 
+    private void clearPendingWtf() {
+        if (mPendingWtf != null) {
+            mHandler.removeCallbacks(mPendingWtf);
+            mPendingWtf = null;
+        }
+    }
+
     @Override
     public synchronized void onSensorChanged(SensorEvent event) {
         mDataCollector.onSensorChanged(event);
@@ -224,6 +255,7 @@
             FalsingLog.i("onScreenTurningOn", new StringBuilder()
                     .append("from=").append(mScreenOn ? 1 : 0)
                     .toString());
+            clearPendingWtf();
         }
         mScreenOn = true;
         if (sessionEntrypoint()) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index 13e047c..6a868d5 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -218,7 +218,8 @@
                     Preconditions.checkState(mState == State.DOZE_REQUEST_PULSE);
                     break;
                 case DOZE_PULSE_DONE:
-                    Preconditions.checkState(mState == State.DOZE_PULSING);
+                    Preconditions.checkState(
+                            mState == State.DOZE_REQUEST_PULSE || mState == State.DOZE_PULSING);
                     break;
                 default:
                     break;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index c19e806..d4da9a4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -17,6 +17,8 @@
 package com.android.systemui.keyguard;
 
 import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
+
+import static com.android.internal.telephony.IccCardConstants.State.ABSENT;
 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;
@@ -429,7 +431,11 @@
                                 resetStateLocked();
                             }
                         }
-                        onSimNotReadyLocked();
+                        if (simState == ABSENT) {
+                            // MVNO SIMs can become transiently NOT_READY when switching networks,
+                            // so we should only lock when they are ABSENT.
+                            onSimAbsentLocked();
+                        }
                     }
                     break;
                 case PIN_REQUIRED:
@@ -456,7 +462,7 @@
                                   + "show permanently disabled message in lockscreen.");
                             resetStateLocked();
                         }
-                        onSimNotReadyLocked();
+                        onSimAbsentLocked();
                     }
                     break;
                 case READY:
@@ -470,22 +476,20 @@
                 default:
                     if (DEBUG_SIM_STATES) Log.v(TAG, "Unspecific state: " + simState);
                     synchronized (KeyguardViewMediator.this) {
-                        onSimNotReadyLocked();
+                        onSimAbsentLocked();
                     }
                     break;
             }
         }
 
-        private void onSimNotReadyLocked() {
+        private void onSimAbsentLocked() {
             if (isSecure() && mLockWhenSimRemoved) {
                 mLockWhenSimRemoved = false;
                 MetricsLogger.action(mContext,
                         MetricsProto.MetricsEvent.ACTION_LOCK_BECAUSE_SIM_REMOVED, mShowing);
                 if (!mShowing) {
-                    if (DEBUG_SIM_STATES) Log.d(TAG, "SIM removed, showing keyguard");
+                    Log.i(TAG, "SIM removed, showing keyguard");
                     doKeyguardLocked(null);
-                } else {
-                    resetStateLocked();
                 }
             }
         }
@@ -1228,7 +1232,7 @@
             // if the setup wizard hasn't run yet, don't show
             final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim", false);
             final boolean absent = SubscriptionManager.isValidSubscriptionId(
-                    mUpdateMonitor.getNextSubIdForState(IccCardConstants.State.ABSENT));
+                    mUpdateMonitor.getNextSubIdForState(ABSENT));
             final boolean disabled = SubscriptionManager.isValidSubscriptionId(
                     mUpdateMonitor.getNextSubIdForState(IccCardConstants.State.PERM_DISABLED));
             final boolean lockedOrMissing = mUpdateMonitor.isSimPinSecure()
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 43cfa32..7e275d8 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -16,9 +16,17 @@
 
 package com.android.systemui.pip.phone;
 
+import static android.view.Display.DEFAULT_DISPLAY;
+
 import android.app.ActivityManager;
 import android.app.IActivityManager;
 import android.content.Context;
+import android.content.pm.ParceledListSlice;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.IPinnedStackController;
+import android.view.IPinnedStackListener;
 import android.view.IWindowManager;
 import android.view.WindowManagerGlobal;
 
@@ -33,10 +41,52 @@
     private Context mContext;
     private IActivityManager mActivityManager;
     private IWindowManager mWindowManager;
+    private Handler mHandler = new Handler();
+
+    private final PinnedStackListener mPinnedStackListener = new PinnedStackListener();
 
     private PipMenuActivityController mMenuController;
     private PipTouchHandler mTouchHandler;
 
+    /**
+     * Handler for messages from the PIP controller.
+     */
+    private class PinnedStackListener extends IPinnedStackListener.Stub {
+
+        @Override
+        public void onListenerRegistered(IPinnedStackController controller) {
+            mHandler.post(() -> {
+                mTouchHandler.setPinnedStackController(controller);
+            });
+        }
+
+        @Override
+        public void onBoundsChanged(boolean adjustedForIme) {
+            // Do nothing
+        }
+
+        @Override
+        public void onActionsChanged(ParceledListSlice actions) {
+            mHandler.post(() -> {
+                mMenuController.setActions(actions);
+            });
+        }
+
+        @Override
+        public void onMinimizedStateChanged(boolean isMinimized) {
+            mHandler.post(() -> {
+                mTouchHandler.onMinimizedStateChanged(isMinimized);
+            });
+        }
+
+        @Override
+        public void onSnapToEdgeStateChanged(boolean isSnapToEdge) {
+            mHandler.post(() -> {
+                mTouchHandler.onSnapToEdgeStateChanged(isSnapToEdge);
+            });
+        }
+    }
+
     private PipManager() {}
 
     /**
@@ -47,6 +97,12 @@
         mActivityManager = ActivityManager.getService();
         mWindowManager = WindowManagerGlobal.getWindowManagerService();
 
+        try {
+            mWindowManager.registerPinnedStackListener(DEFAULT_DISPLAY, mPinnedStackListener);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to register pinned stack listener", e);
+        }
+
         mMenuController = new PipMenuActivityController(context, mActivityManager, mWindowManager);
         mTouchHandler = new PipTouchHandler(context, mMenuController, mActivityManager,
                 mWindowManager);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index bfe5cff..fe8ee6f 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -19,16 +19,27 @@
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.ActivityManager;
+import android.app.PendingIntent.CanceledException;
+import android.app.RemoteAction;
 import android.content.Intent;
+import android.content.pm.ParceledListSlice;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
 import android.os.Messenger;
 import android.os.RemoteException;
 import android.util.Log;
+import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
 import com.android.systemui.R;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Translucent activity that gets started on top of a task in PIP to allow the user to control it.
  */
@@ -36,16 +47,25 @@
 
     private static final String TAG = "PipMenuActivity";
 
-    public static final int MESSAGE_FINISH_SELF = 2;
+    public static final int MESSAGE_FINISH_SELF = 1;
+    public static final int MESSAGE_UPDATE_ACTIONS = 2;
 
     private static final long INITIAL_DISMISS_DELAY = 2000;
     private static final long POST_INTERACTION_DISMISS_DELAY = 1500;
 
+    private List<RemoteAction> mActions = new ArrayList<>();
+    private View mDismissButton;
+    private View mMinimizeButton;
+
+    private Handler mHandler = new Handler();
     private Messenger mToControllerMessenger;
     private Messenger mMessenger = new Messenger(new Handler() {
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
+                case MESSAGE_UPDATE_ACTIONS:
+                    setActions(((ParceledListSlice) msg.obj).getList());
+                    break;
                 case MESSAGE_FINISH_SELF:
                     finish();
                     break;
@@ -63,15 +83,27 @@
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-
-        Intent startingIntet = getIntent();
-        mToControllerMessenger = startingIntet.getParcelableExtra(
-                PipMenuActivityController.EXTRA_CONTROLLER_MESSENGER);
-
         setContentView(R.layout.pip_menu_activity);
-        findViewById(R.id.expand_pip).setOnClickListener((view) -> {
-            finish();
-            notifyExpandPip();
+
+        Intent startingIntent = getIntent();
+        mToControllerMessenger = startingIntent.getParcelableExtra(
+                PipMenuActivityController.EXTRA_CONTROLLER_MESSENGER);
+        ParceledListSlice actions = startingIntent.getParcelableExtra(
+                PipMenuActivityController.EXTRA_ACTIONS);
+        if (actions != null) {
+            setActions(actions.getList());
+        }
+
+        findViewById(R.id.menu).setOnClickListener((v) -> {
+            expandPip();
+        });
+        mDismissButton = findViewById(R.id.dismiss);
+        mDismissButton.setOnClickListener((v) -> {
+            dismissPip();
+        });
+        mMinimizeButton = findViewById(R.id.minimize);
+        mMinimizeButton.setOnClickListener((v) -> {
+            minimizePip();
         });
     }
 
@@ -107,25 +139,74 @@
         // Do nothing
     }
 
+    private void setActions(List<RemoteAction> actions) {
+        mActions.clear();
+        mActions.addAll(actions);
+        updateActionViews();
+    }
+
+    private void updateActionViews() {
+        ViewGroup actionsContainer = (ViewGroup) findViewById(R.id.actions);
+        if (actionsContainer != null) {
+            actionsContainer.removeAllViews();
+
+            // Recreate the layout
+            final LayoutInflater inflater = LayoutInflater.from(this);
+            for (int i = 0; i < mActions.size(); i++) {
+                final RemoteAction action = mActions.get(i);
+                final ViewGroup actionContainer = (ViewGroup) inflater.inflate(
+                        R.layout.pip_menu_action, actionsContainer, false);
+                actionContainer.setOnClickListener((v) -> {
+                    action.sendActionInvoked();
+                });
+
+                final TextView title = (TextView) actionContainer.findViewById(R.id.title);
+                title.setText(action.getTitle());
+                title.setContentDescription(action.getContentDescription());
+
+                final ImageView icon = (ImageView) actionContainer.findViewById(R.id.icon);
+                action.getIcon().loadDrawableAsync(this, (d) -> {
+                    icon.setImageDrawable(d);
+                }, mHandler);
+                actionsContainer.addView(actionContainer);
+            }
+        }
+    }
+
     private void notifyActivityVisibility(boolean visible) {
         Message m = Message.obtain();
         m.what = PipMenuActivityController.MESSAGE_ACTIVITY_VISIBILITY_CHANGED;
         m.arg1 = visible ? 1 : 0;
         m.replyTo = visible ? mMessenger : null;
-        try {
-            mToControllerMessenger.send(m);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Could not notify controller of PIP menu visibility", e);
-        }
+        sendMessage(m, "Could not notify controller of PIP menu visibility");
     }
 
-    private void notifyExpandPip() {
+    private void expandPip() {
+        sendEmptyMessage(PipMenuActivityController.MESSAGE_EXPAND_PIP,
+                "Could not notify controller to expand PIP");
+    }
+
+    private void minimizePip() {
+        sendEmptyMessage(PipMenuActivityController.MESSAGE_MINIMIZE_PIP,
+                "Could not notify controller to minimize PIP");
+    }
+
+    private void dismissPip() {
+        sendEmptyMessage(PipMenuActivityController.MESSAGE_DISMISS_PIP,
+                "Could not notify controller to dismiss PIP");
+    }
+
+    private void sendEmptyMessage(int what, String errorMsg) {
         Message m = Message.obtain();
-        m.what = PipMenuActivityController.MESSAGE_EXPAND_PIP;
+        m.what = what;
+        sendMessage(m, errorMsg);
+    }
+
+    private void sendMessage(Message m, String errorMsg) {
         try {
             mToControllerMessenger.send(m);
         } catch (RemoteException e) {
-            Log.e(TAG, "Could not notify controller to expand PIP", e);
+            Log.e(TAG, errorMsg, e);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index d1bce0c..64e2d1a 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -1,14 +1,13 @@
 package com.android.systemui.pip.phone;
 
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.view.WindowManager.INPUT_CONSUMER_PIP;
 
 import android.app.ActivityManager.StackInfo;
 import android.app.ActivityOptions;
 import android.app.IActivityManager;
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.Rect;
+import android.content.pm.ParceledListSlice;
 import android.os.Handler;
 import android.os.Message;
 import android.os.Messenger;
@@ -24,8 +23,12 @@
     private static final String TAG = "PipMenuActivityController";
 
     public static final String EXTRA_CONTROLLER_MESSENGER = "messenger";
-    public static final int MESSAGE_ACTIVITY_VISIBILITY_CHANGED = 1;
-    public static final int MESSAGE_EXPAND_PIP = 3;
+    public static final String EXTRA_ACTIONS = "actions";
+
+    public static final int MESSAGE_ACTIVITY_VISIBILITY_CHANGED = 100;
+    public static final int MESSAGE_EXPAND_PIP = 101;
+    public static final int MESSAGE_MINIMIZE_PIP = 102;
+    public static final int MESSAGE_DISMISS_PIP = 103;
 
     /**
      * A listener interface to receive notification on changes in PIP.
@@ -35,12 +38,29 @@
          * Called when the PIP menu visibility changes.
          */
         void onPipMenuVisibilityChanged(boolean visible);
+
+        /**
+         * Called when the PIP requested to be expanded.
+         */
+        void onPipExpand();
+
+        /**
+         * Called when the PIP requested to be minimized.
+         */
+        void onPipMinimize();
+
+        /**
+         * Called when the PIP requested to be expanded.
+         */
+        void onPipDismiss();
     }
 
     private Context mContext;
     private IActivityManager mActivityManager;
     private IWindowManager mWindowManager;
+
     private ArrayList<Listener> mListeners = new ArrayList<>();
+    private ParceledListSlice mActions;
 
     private Messenger mToActivityMessenger;
     private Messenger mMessenger = new Messenger(new Handler() {
@@ -57,10 +77,23 @@
                     break;
                 }
                 case MESSAGE_EXPAND_PIP: {
-                    try {
-                        mActivityManager.resizeStack(PINNED_STACK_ID, null, true, true, true, 225);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Error showing PIP menu activity", e);
+                    int listenerCount = mListeners.size();
+                    for (int i = 0; i < listenerCount; i++) {
+                        mListeners.get(i).onPipExpand();
+                    }
+                    break;
+                }
+                case MESSAGE_MINIMIZE_PIP: {
+                    int listenerCount = mListeners.size();
+                    for (int i = 0; i < listenerCount; i++) {
+                        mListeners.get(i).onPipMinimize();
+                    }
+                    break;
+                }
+                case MESSAGE_DISMISS_PIP: {
+                    int listenerCount = mListeners.size();
+                    for (int i = 0; i < listenerCount; i++) {
+                        mListeners.get(i).onPipDismiss();
                     }
                     break;
                 }
@@ -95,6 +128,7 @@
                     pinnedStackInfo.taskIds.length > 0) {
                 Intent intent = new Intent(mContext, PipMenuActivity.class);
                 intent.putExtra(EXTRA_CONTROLLER_MESSENGER, mMessenger);
+                intent.putExtra(EXTRA_ACTIONS, mActions);
                 ActivityOptions options = ActivityOptions.makeBasic();
                 options.setLaunchTaskId(
                         pinnedStackInfo.taskIds[pinnedStackInfo.taskIds.length - 1]);
@@ -123,4 +157,22 @@
             mToActivityMessenger = null;
         }
     }
+
+    /**
+     * Sets the {@param actions} associated with the PiP.
+     */
+    public void setActions(ParceledListSlice actions) {
+        mActions = actions;
+
+        if (mToActivityMessenger != null) {
+            Message m = Message.obtain();
+            m.what = PipMenuActivity.MESSAGE_UPDATE_ACTIONS;
+            m.obj = actions;
+            try {
+                mToActivityMessenger.send(m);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Could not notify menu activity to update actions", e);
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 09671e7..ff3cc79 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -17,7 +17,6 @@
 package com.android.systemui.pip.phone;
 
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.INPUT_CONSUMER_PIP;
 
 import static com.android.systemui.Interpolators.FAST_OUT_LINEAR_IN;
@@ -38,7 +37,6 @@
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.IPinnedStackController;
-import android.view.IPinnedStackListener;
 import android.view.IWindowManager;
 import android.view.InputChannel;
 import android.view.InputEvent;
@@ -80,7 +78,6 @@
     private final IActivityManager mActivityManager;
     private final IWindowManager mWindowManager;
     private final ViewConfiguration mViewConfig;
-    private final PinnedStackListener mPinnedStackListener = new PinnedStackListener();
     private final PipMenuListener mMenuListener = new PipMenuListener();
     private IPinnedStackController mPinnedStackController;
 
@@ -149,26 +146,6 @@
     }
 
     /**
-     * Handler for messages from the PIP controller.
-     */
-    private class PinnedStackListener extends IPinnedStackListener.Stub {
-
-        @Override
-        public void onListenerRegistered(IPinnedStackController controller) {
-            mPinnedStackController = controller;
-
-            // Update the controller with the current tuner state
-            setMinimizedState(mIsMinimized);
-            setSnapToEdge(mEnableSnapToEdge);
-        }
-
-        @Override
-        public void onBoundsChanged(boolean adjustedForIme) {
-            // Do nothing
-        }
-    }
-
-    /**
      * A listener for the PIP menu activity.
      */
     private class PipMenuListener implements PipMenuActivityController.Listener {
@@ -181,17 +158,30 @@
                 unregisterInputConsumer();
             }
         }
+
+        @Override
+        public void onPipExpand() {
+            if (!mIsMinimized) {
+                expandPinnedStackToFullscreen();
+            }
+        }
+
+        @Override
+        public void onPipMinimize() {
+            setMinimizedState(true);
+            animateToClosestMinimizedTarget();
+        }
+
+        @Override
+        public void onPipDismiss() {
+            animateDismissPinnedStack(mPinnedStackBounds);
+        }
     }
 
     public PipTouchHandler(Context context, PipMenuActivityController menuController,
             IActivityManager activityManager, IWindowManager windowManager) {
 
         // Initialize the Pip input consumer
-        try {
-            windowManager.registerPinnedStackListener(DEFAULT_DISPLAY, mPinnedStackListener);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to create PIP input consumer", e);
-        }
         mContext = context;
         mActivityManager = activityManager;
         mWindowManager = windowManager;
@@ -255,6 +245,14 @@
         updateBoundedPinnedStackBounds(false /* updatePinnedStackBounds */);
     }
 
+    public void onMinimizedStateChanged(boolean isMinimized) {
+        mIsMinimized = isMinimized;
+    }
+
+    public void onSnapToEdgeStateChanged(boolean isSnapToEdge) {
+        mSnapAlgorithm.setSnapToEdge(isSnapToEdge);
+    }
+
     private boolean handleTouchEvent(MotionEvent ev) {
         // Skip touch handling until we are bound to the controller
         if (mPinnedStackController == null) {
@@ -353,10 +351,17 @@
     }
 
     /**
-     * Sets the snap-to-edge state.
+     * Sets the controller to update the system of changes from user interaction.
+     */
+    void setPinnedStackController(IPinnedStackController controller) {
+        mPinnedStackController = controller;
+    }
+
+    /**
+     * Sets the snap-to-edge state and notifies the controller.
      */
     private void setSnapToEdge(boolean snapToEdge) {
-        mSnapAlgorithm.setSnapToEdge(snapToEdge);
+        onSnapToEdgeStateChanged(snapToEdge);
 
         if (mPinnedStackController != null) {
             try {
@@ -371,7 +376,7 @@
      * Sets the minimized state and notifies the controller.
      */
     private void setMinimizedState(boolean isMinimized) {
-        mIsMinimized = isMinimized;
+        onMinimizedStateChanged(isMinimized);
 
         if (mPinnedStackController != null) {
             try {
@@ -432,6 +437,12 @@
         mPinnedStackBoundsAnimator = mMotionHelper.createAnimationToBounds(mPinnedStackBounds,
                 toBounds, MINIMIZE_STACK_MAX_DURATION, LINEAR_OUT_SLOW_IN,
                 mUpdatePinnedStackBoundsListener);
+        mPinnedStackBoundsAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mMenuController.hideMenu();
+            }
+        });
         mPinnedStackBoundsAnimator.start();
     }
 
@@ -759,7 +770,8 @@
 
         @Override
         public boolean onUp(PipTouchState touchState) {
-            if (mEnableTapThrough && !touchState.isDragging() && !mIsTappingThrough) {
+            if (mEnableTapThrough && !touchState.isDragging() && !mIsMinimized &&
+                    !mIsTappingThrough) {
                 mMenuController.showMenu();
                 mIsTappingThrough = true;
                 return true;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
index 17d9864..2e84ced 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
@@ -16,11 +16,7 @@
 
 package com.android.systemui.pip.phone;
 
-import android.app.IActivityManager;
 import android.graphics.PointF;
-import android.view.IPinnedStackController;
-import android.view.IPinnedStackListener;
-import android.view.IWindowManager;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.ViewConfiguration;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 790f3f6..d9fc2fc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -207,8 +207,6 @@
                 getSystemService(Context.UI_MODE_SERVICE);
         if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
             mImpl = new RecentsTvImpl(mContext);
-        } else if (SystemProperties.getBoolean("ro.recents.grid", false) == true) {
-            mImpl = new RecentsGridImpl(mContext);
         } else {
             mImpl = new RecentsImpl(mContext);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 73c6e6e..711f0c6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -20,6 +20,7 @@
 import android.content.res.Resources;
 import android.graphics.Rect;
 
+import android.os.SystemProperties;
 import com.android.systemui.R;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 
@@ -58,6 +59,10 @@
     public boolean fakeShadows;
     public int svelteLevel;
 
+    // Whether this product supports Grid-based Recents. If this is field is set to true, then
+    // Recents will layout task views in a grid mode when there's enough space in the screen.
+    public boolean isGridEnabled;
+
     public RecentsConfiguration(Context context) {
         // Load only resources that can not change after the first load either through developer
         // settings or via multi window
@@ -66,6 +71,7 @@
         Resources res = appContext.getResources();
         fakeShadows = res.getBoolean(R.bool.config_recents_fake_shadows);
         svelteLevel = res.getInteger(R.integer.recents_svelte_level);
+        isGridEnabled = SystemProperties.getBoolean("ro.recents.grid", false);
 
         float screenDensity = context.getResources().getDisplayMetrics().density;
         smallestWidth = ssp.getDeviceSmallestWidth();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index cf75c4f..002515d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -27,6 +27,7 @@
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
+import android.os.Binder;
 import android.os.RemoteException;
 import android.util.DisplayMetrics;
 import android.view.Gravity;
@@ -106,6 +107,7 @@
                         | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
                 ,
                 PixelFormat.TRANSLUCENT);
+        lp.token = new Binder();
         lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
         lp.setTitle("ScreenPinningConfirmation");
         lp.gravity = Gravity.FILL;
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 ea50d89..ddffea2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -74,6 +74,7 @@
 import android.view.WindowManager.KeyboardShortcutsReceiver;
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityManager;
+import android.app.KeyguardManager;
 
 import com.android.internal.app.AssistUtils;
 import com.android.internal.os.BackgroundThread;
@@ -124,6 +125,7 @@
     AssistUtils mAssistUtils;
     WindowManager mWm;
     IWindowManager mIwm;
+    KeyguardManager mKgm;
     UserManager mUm;
     Display mDisplay;
     String mRecentsPackage;
@@ -212,6 +214,7 @@
         mAssistUtils = new AssistUtils(context);
         mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
         mIwm = WindowManagerGlobal.getWindowManagerService();
+        mKgm = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
         mUm = UserManager.get(context);
         mDisplay = mWm.getDefaultDisplay();
         mRecentsPackage = context.getPackageName();
@@ -862,6 +865,16 @@
         return label;
     }
 
+    /**
+     * Returns whether the provided {@param userId} is currently locked (and showing Keyguard).
+     */
+    public boolean isDeviceLocked(int userId) {
+        if (mKgm == null) {
+            return false;
+        }
+        return mKgm.isDeviceLocked(userId);
+    }
+
     /** Returns the package name of the home activity. */
     public String getHomeActivityPackageName() {
         if (mPm == null) return null;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
index 2c5c437..4349e30 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
@@ -86,7 +86,7 @@
     public static <T extends View> T findParent(View v, Class<T> parentClass) {
         ViewParent parent = v.getParent();
         while (parent != null) {
-            if (parent.getClass().equals(parentClass)) {
+            if (parentClass.isAssignableFrom(parent.getClass())) {
                 return (T) parent;
             }
             parent = parent.getParent();
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 9b48e4d..5877440 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -28,6 +28,7 @@
 import android.os.UserManager;
 import android.util.ArraySet;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 
 import com.android.systemui.Prefs;
@@ -130,6 +131,7 @@
 
         SparseArray<Task.TaskKey> affiliatedTasks = new SparseArray<>();
         SparseIntArray affiliatedTaskCounts = new SparseIntArray();
+        SparseBooleanArray lockedUsers = new SparseBooleanArray();
         String dismissDescFormat = mContext.getString(
                 R.string.accessibility_recents_item_will_be_dismissed);
         String appInfoDescFormat = mContext.getString(
@@ -177,12 +179,17 @@
             int backgroundColor = loader.getActivityBackgroundColor(t.taskDescription);
             boolean isSystemApp = (info != null) &&
                     ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
+            if (lockedUsers.indexOfKey(t.userId) < 0) {
+                lockedUsers.put(t.userId, Recents.getSystemServices().isDeviceLocked(t.userId));
+            }
+            boolean isLocked = lockedUsers.get(t.userId);
 
             // Add the task to the stack
             Task task = new Task(taskKey, t.affiliatedTaskId, t.affiliatedTaskColor, icon,
                     thumbnail, title, titleDescription, dismissDescription, appInfoDescription,
                     activityColor, backgroundColor, isLaunchTarget, isStackTask, isSystemApp,
-                    t.isDockable, t.bounds, t.taskDescription, t.resizeMode, t.topActivity);
+                    t.isDockable, t.bounds, t.taskDescription, t.resizeMode, t.topActivity,
+                    isLocked);
 
             allTasks.add(task);
             affiliatedTaskCounts.put(taskKey.id, affiliatedTaskCounts.get(taskKey.id, 0) + 1);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 86a0315..53f713a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -189,6 +189,9 @@
     @ViewDebug.ExportedProperty(category="recents")
     public ComponentName topActivity;
 
+    @ViewDebug.ExportedProperty(category="recents")
+    public boolean isLocked;
+
     private ArrayList<TaskCallbacks> mCallbacks = new ArrayList<>();
 
     public Task() {
@@ -200,7 +203,7 @@
                 String appInfoDescription, int colorPrimary, int colorBackground,
                 boolean isLaunchTarget, boolean isStackTask, boolean isSystemApp,
                 boolean isDockable, Rect bounds, ActivityManager.TaskDescription taskDescription,
-                int resizeMode, ComponentName topActivity) {
+                int resizeMode, ComponentName topActivity, boolean isLocked) {
         boolean isInAffiliationGroup = (affiliationTaskId != key.id);
         boolean hasAffiliationGroupColor = isInAffiliationGroup && (affiliationColor != 0);
         this.key = key;
@@ -224,6 +227,7 @@
         this.isDockable = isDockable;
         this.resizeMode = resizeMode;
         this.topActivity = topActivity;
+        this.isLocked = isLocked;
     }
 
     /**
@@ -250,6 +254,7 @@
         this.isSystemApp = o.isSystemApp;
         this.isDockable = o.isDockable;
         this.resizeMode = o.resizeMode;
+        this.isLocked = o.isLocked;
         this.topActivity = o.topActivity;
     }
 
@@ -355,6 +360,9 @@
         if (isFreeformTask()) {
             writer.print(" freeform=Y");
         }
+        if (isLocked) {
+            writer.print(" locked=Y");
+        }
         writer.print(" "); writer.print(title);
         writer.println();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
index 253d06a..dba085e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
@@ -30,17 +30,17 @@
     private static final float MIN_ALPHA = 0.1f;
     private static final float MAX_ALPHA = 0.8f;
 
-    View mSourceView;
+    protected View mSourceView;
     @ViewDebug.ExportedProperty(category="recents")
-    Rect mClipRect = new Rect();
+    protected Rect mClipRect = new Rect();
     @ViewDebug.ExportedProperty(category="recents")
-    Rect mClipBounds = new Rect();
+    protected Rect mClipBounds = new Rect();
     @ViewDebug.ExportedProperty(category="recents")
-    Rect mLastClipBounds = new Rect();
+    protected Rect mLastClipBounds = new Rect();
     @ViewDebug.ExportedProperty(category="recents")
-    int mCornerRadius;
+    protected int mCornerRadius;
     @ViewDebug.ExportedProperty(category="recents")
-    float mAlpha = 1f;
+    protected float mAlpha = 1f;
 
     public AnimateableViewBounds(View source, int cornerRadius) {
         mSourceView = source;
@@ -110,7 +110,7 @@
         return mClipRect.bottom;
     }
 
-    private void updateClipBounds() {
+    protected void updateClipBounds() {
         mClipBounds.set(Math.max(0, mClipRect.left), Math.max(0, mClipRect.top),
                 mSourceView.getWidth() - Math.max(0, mClipRect.right),
                 mSourceView.getHeight() - Math.max(0, mClipRect.bottom));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
index 493e618..c1f4c8a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -157,7 +157,7 @@
 
             // Get the current transform for the task, which will be used to position it offscreen
             stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform,
-                    null);
+                    null, mStackView.useGridLayout());
 
             if (hideTask) {
                 tv.setVisibility(View.INVISIBLE);
@@ -230,7 +230,7 @@
             // Get the current transform for the task, which will be updated to the final transform
             // to animate to depending on how recents was invoked
             stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform,
-                    null);
+                    null, mStackView.useGridLayout());
 
             if (launchState.launchedFromApp && !launchState.launchedViaDockGesture) {
                 if (task.isLaunchTarget) {
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 571c0f6..3c97310 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -38,7 +38,7 @@
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
-
+import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -326,7 +326,7 @@
     @ViewDebug.ExportedProperty(category="recents")
     int mMinTranslationZ;
     @ViewDebug.ExportedProperty(category="recents")
-    int mMaxTranslationZ;
+    public int mMaxTranslationZ;
 
     // Optimization, allows for quick lookup of task -> index
     private SparseIntArray mTaskIndexMap = new SparseIntArray();
@@ -334,6 +334,7 @@
 
     // The freeform workspace layout
     FreeformWorkspaceLayoutAlgorithm mFreeformLayoutAlgorithm;
+    TaskGridLayoutAlgorithm mTaskGridLayoutAlgorithm;
 
     // The transform to place TaskViews at the front and back of the stack respectively
     TaskViewTransform mBackOfStackTransform = new TaskViewTransform();
@@ -344,6 +345,7 @@
         mContext = context;
         mCb = cb;
         mFreeformLayoutAlgorithm = new FreeformWorkspaceLayoutAlgorithm(context);
+        mTaskGridLayoutAlgorithm = new TaskGridLayoutAlgorithm(context);
         reloadOnConfigurationChange(context);
     }
 
@@ -377,6 +379,7 @@
                 R.dimen.recents_layout_initial_bottom_offset_tablet,
                 R.dimen.recents_layout_initial_bottom_offset_tablet);
         mFreeformLayoutAlgorithm.reloadOnConfigurationChange(context);
+        mTaskGridLayoutAlgorithm.reloadOnConfigurationChange(context);
         mMinMargin = res.getDimensionPixelSize(R.dimen.recents_layout_min_margin);
         mBaseTopMargin = getDimensionForDevice(context,
                 R.dimen.recents_layout_top_margin_phone,
@@ -470,6 +473,9 @@
 
             updateFrontBackTransforms();
         }
+
+        // Initialize the grid layout
+        mTaskGridLayoutAlgorithm.initialize(displayRect, windowRect);
     }
 
     /**
@@ -825,24 +831,30 @@
      * is what the view is measured and laid out with.
      */
     public TaskViewTransform getStackTransform(Task task, float stackScroll,
-            TaskViewTransform transformOut, TaskViewTransform frontTransform) {
+            TaskViewTransform transformOut, TaskViewTransform frontTransform,
+            boolean useGridLayout) {
         return getStackTransform(task, stackScroll, mFocusState, transformOut, frontTransform,
-                false /* forceUpdate */, false /* ignoreTaskOverrides */);
+                false /* forceUpdate */, false /* ignoreTaskOverrides */, useGridLayout);
     }
 
     public TaskViewTransform getStackTransform(Task task, float stackScroll,
             TaskViewTransform transformOut, TaskViewTransform frontTransform,
-            boolean ignoreTaskOverrides) {
+            boolean ignoreTaskOverrides, boolean useGridLayout) {
         return getStackTransform(task, stackScroll, mFocusState, transformOut, frontTransform,
-                false /* forceUpdate */, ignoreTaskOverrides);
+                false /* forceUpdate */, ignoreTaskOverrides, useGridLayout);
     }
 
     public TaskViewTransform getStackTransform(Task task, float stackScroll, int focusState,
             TaskViewTransform transformOut, TaskViewTransform frontTransform, boolean forceUpdate,
-            boolean ignoreTaskOverrides) {
+            boolean ignoreTaskOverrides, boolean useGridLayout) {
         if (mFreeformLayoutAlgorithm.isTransformAvailable(task, this)) {
             mFreeformLayoutAlgorithm.getTransform(task, transformOut, this);
             return transformOut;
+        } else if (useGridLayout) {
+            int taskIndex = mTaskIndexMap.get(task.key.id);
+            int taskCount = mTaskIndexMap.size();
+            mTaskGridLayoutAlgorithm.getTransform(taskIndex, taskCount, transformOut, this);
+            return transformOut;
         } else {
             // Return early if we have an invalid index
             int nonOverrideTaskProgress = mTaskIndexMap.get(task.key.id, -1);
@@ -867,7 +879,7 @@
             Rect windowOverrideRect) {
         TaskViewTransform transform = getStackTransform(task, stackScroll, mFocusState,
                 transformOut, frontTransform, true /* forceUpdate */,
-                false /* ignoreTaskOverrides */);
+                false /* ignoreTaskOverrides */, false /* useGridLayout */);
         return transformToScreenCoordinates(transform, windowOverrideRect);
     }
 
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 8c94c35..57fde67 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -92,6 +92,7 @@
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
 
+import com.android.systemui.recents.views.grid.GridTaskView;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -158,6 +159,7 @@
     private int mTaskCornerRadiusPx;
     private int mDividerSize;
     private int mStartTimerIndicatorDuration;
+    private boolean mDraggingOverDockState;
 
     @ViewDebug.ExportedProperty(category="recents")
     private boolean mTaskViewsClipDirty = true;
@@ -499,13 +501,13 @@
 
             // Calculate the current and (if necessary) the target transform for the task
             transform = mLayoutAlgorithm.getStackTransform(task, curStackScroll,
-                    taskTransforms.get(i), frontTransform, ignoreTaskOverrides);
+                    taskTransforms.get(i), frontTransform, ignoreTaskOverrides, useGridLayout());
             if (useTargetStackScroll && !transform.visible) {
                 // If we have a target stack scroll and the task is not currently visible, then we
                 // just update the transform at the new scroll
                 // TODO: Optimize this
-                transformAtTarget = mLayoutAlgorithm.getStackTransform(task,
-                        targetStackScroll, new TaskViewTransform(), frontTransformAtTarget);
+                transformAtTarget = mLayoutAlgorithm.getStackTransform(task, targetStackScroll,
+                    new TaskViewTransform(), frontTransformAtTarget, useGridLayout());
                 if (transformAtTarget.visible) {
                     transform.copyFrom(transformAtTarget);
                 }
@@ -736,7 +738,7 @@
             } else {
                 mLayoutAlgorithm.getStackTransform(task, mStackScroller.getStackScroll(),
                         focusState, transform, null, true /* forceUpdate */,
-                        false /* ignoreTaskOverrides */);
+                        false /* ignoreTaskOverrides */, useGridLayout());
             }
             transform.visible = true;
         }
@@ -753,7 +755,7 @@
             Task task = tasks.get(i);
             TaskViewTransform transform = transformsOut.get(i);
             mLayoutAlgorithm.getStackTransform(task, stackScroll, focusState, transform, null,
-                    true /* forceUpdate */, ignoreTaskOverrides);
+                    true /* forceUpdate */, ignoreTaskOverrides, useGridLayout());
             transform.visible = true;
         }
     }
@@ -782,6 +784,11 @@
      * Updates the clip for each of the task views from back to front.
      */
     private void clipTaskViews() {
+        // We never clip task views in grid layout
+        if (Recents.getConfiguration().isGridEnabled) {
+            return;
+        }
+
         // Update the clip on each task child
         List<TaskView> taskViews = getTaskViews();
         TaskView tmpTv = null;
@@ -1506,7 +1513,11 @@
 
     @Override
     public TaskView createView(Context context) {
-        return (TaskView) mInflater.inflate(R.layout.recents_task_view, this, false);
+        if (Recents.getConfiguration().isGridEnabled) {
+            return (GridTaskView) mInflater.inflate(R.layout.recents_grid_task_view, this, false);
+        } else {
+            return (TaskView) mInflater.inflate(R.layout.recents_task_view, this, false);
+        }
     }
 
     @Override
@@ -1830,7 +1841,7 @@
         // Enlarge the dragged view slightly
         float finalScale = event.taskView.getScaleX() * DRAG_SCALE_FACTOR;
         mLayoutAlgorithm.getStackTransform(event.task, getScroller().getStackScroll(),
-                mTmpTransform, null);
+                mTmpTransform, null, useGridLayout());
         mTmpTransform.scale = finalScale;
         mTmpTransform.translationZ = mLayoutAlgorithm.mMaxTranslationZ + 1;
         mTmpTransform.dimAlpha = 0f;
@@ -1851,6 +1862,7 @@
                 Interpolators.FAST_OUT_SLOW_IN);
         boolean ignoreTaskOverrides = false;
         if (event.dropTarget instanceof TaskStack.DockState) {
+            mDraggingOverDockState = true;
             // Calculate the new task stack bounds that matches the window size that Recents will
             // have after the drop
             final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
@@ -1870,6 +1882,7 @@
             updateLayoutAlgorithm(true /* boundScroll */);
             ignoreTaskOverrides = true;
         } else {
+            mDraggingOverDockState = false;
             // Restore the pre-drag task stack bounds, but ensure that we don't layout the dragging
             // task view, so add it back to the ignore set after updating the layout
             removeIgnoreTask(event.task);
@@ -1880,6 +1893,7 @@
     }
 
     public final void onBusEvent(final DragEndEvent event) {
+        mDraggingOverDockState = false;
         // We don't handle drops on the dock regions
         if (event.dropTarget instanceof TaskStack.DockState) {
             // However, we do need to reset the overrides, since the last state of this task stack
@@ -2119,6 +2133,20 @@
     }
 
     /**
+     * Check whether we should use the grid layout.
+     * We use the grid layout for Recents iff all the following is true:
+     *  1. Grid-mode is enabled.
+     *  2. The activity is not in multi-window mode.
+     *  3. The user is not dragging a task view over the dock state.
+     * @return True if we should use the grid layout.
+     */
+    public boolean useGridLayout() {
+        return Recents.getConfiguration().isGridEnabled
+            && !((RecentsActivity) mContext).isInMultiWindowMode()
+            && !mDraggingOverDockState;
+    }
+
+    /**
      * Reads current system flags related to accessibility and screen pinning.
      */
     private void readSystemFlags() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index de7def6..9b30515 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -176,8 +176,7 @@
         super(context, attrs, defStyleAttr, defStyleRes);
         RecentsConfiguration config = Recents.getConfiguration();
         Resources res = context.getResources();
-        mViewBounds = new AnimateableViewBounds(this, res.getDimensionPixelSize(
-                R.dimen.recents_task_view_shadow_rounded_corners_radius));
+        mViewBounds = createOutlineProvider();
         if (config.fakeShadows) {
             setBackground(new FakeShadowDrawable(res, config));
         }
@@ -207,6 +206,12 @@
         return mTask;
     }
 
+    /* Create an outline provider to clip and outline the view */
+    protected AnimateableViewBounds createOutlineProvider() {
+        return new AnimateableViewBounds(this, mContext.getResources().getDimensionPixelSize(
+            R.dimen.recents_task_view_shadow_rounded_corners_radius));
+    }
+
     /** Returns the view bounds. */
     AnimateableViewBounds getViewBounds() {
         return mViewBounds;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index c46adf1..780cbca 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -67,6 +67,7 @@
     private float mDimAlpha;
     private Matrix mScaleMatrix = new Matrix();
     private Paint mDrawPaint = new Paint();
+    private Paint mLockedPaint = new Paint();
     private Paint mBgFillPaint = new Paint();
     private BitmapShader mBitmapShader;
     private LightingColorFilter mLightingColorFilter = new LightingColorFilter(0xffffffff, 0);
@@ -102,6 +103,7 @@
         mCornerRadius = getResources().getDimensionPixelSize(
                 R.dimen.recents_task_view_rounded_corners_radius);
         mBgFillPaint.setColor(Color.WHITE);
+        mLockedPaint.setColor(Color.WHITE);
         mFullscreenThumbnailScale = context.getResources().getFraction(
                 com.android.internal.R.fraction.thumbnail_fullscreen_scale, 1, 1);
     }
@@ -133,7 +135,11 @@
                 (int) (mThumbnailRect.width() * mThumbnailScale));
         int thumbnailHeight = Math.min(viewHeight,
                 (int) (mThumbnailRect.height() * mThumbnailScale));
-        if (mBitmapShader != null && thumbnailWidth > 0 && thumbnailHeight > 0) {
+
+        if (mTask.isLocked) {
+            canvas.drawRoundRect(0, 0, viewWidth, viewHeight, mCornerRadius, mCornerRadius,
+                    mLockedPaint);
+        } else if (mBitmapShader != null && thumbnailWidth > 0 && thumbnailHeight > 0) {
             int topOffset = mTaskBar != null
                     ? mTaskBar.getHeight() - mCornerRadius
                     : 0;
@@ -200,11 +206,13 @@
                 ColorMatrixColorFilter filter = new ColorMatrixColorFilter(TMP_FILTER_COLOR_MATRIX);
                 mDrawPaint.setColorFilter(filter);
                 mBgFillPaint.setColorFilter(filter);
+                mLockedPaint.setColorFilter(filter);
             } else {
                 mLightingColorFilter.setColorMultiply(Color.argb(255, mul, mul, mul));
                 mDrawPaint.setColorFilter(mLightingColorFilter);
                 mDrawPaint.setColor(0xFFffffff);
                 mBgFillPaint.setColorFilter(mLightingColorFilter);
+                mLockedPaint.setColorFilter(mLightingColorFilter);
             }
         } else {
             int grey = mul;
@@ -299,6 +307,7 @@
         if (t.colorBackground != 0) {
             mBgFillPaint.setColor(t.colorBackground);
         }
+        mLockedPaint.setColor(t.colorPrimary);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/AnimateableGridViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/AnimateableGridViewBounds.java
new file mode 100644
index 0000000..a029478
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/AnimateableGridViewBounds.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.recents.views.grid;
+
+import android.view.View;
+import com.android.systemui.recents.views.AnimateableViewBounds;
+
+/* An outline provider for grid-based task views. */
+class AnimateableGridViewBounds extends AnimateableViewBounds {
+
+    public AnimateableGridViewBounds(View source, int cornerRadius) {
+        super(source, cornerRadius);
+    }
+
+    @Override
+    protected void updateClipBounds() {
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java
new file mode 100644
index 0000000..da14e2b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.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 com.android.systemui.recents.views.grid;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import com.android.systemui.R;
+import com.android.systemui.recents.views.AnimateableViewBounds;
+import com.android.systemui.recents.views.TaskView;
+
+public class GridTaskView extends TaskView {
+    public GridTaskView(Context context) {
+        this(context, null);
+    }
+
+    public GridTaskView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public GridTaskView(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public GridTaskView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    @Override
+    protected AnimateableViewBounds createOutlineProvider() {
+        return new AnimateableGridViewBounds(this, mContext.getResources().getDimensionPixelSize(
+            R.dimen.recents_task_view_shadow_rounded_corners_radius));
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
new file mode 100644
index 0000000..8d1bec8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
@@ -0,0 +1,88 @@
+/*
+ * 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.views.grid;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import com.android.systemui.R;
+import com.android.systemui.recents.misc.Utilities;
+import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
+import com.android.systemui.recents.views.TaskViewTransform;
+
+public class TaskGridLayoutAlgorithm  {
+
+    private int mPaddingLeftRight;
+    private int mPaddingTopBottom;
+    private int mPaddingTaskView;
+
+    private Rect mDisplayRect;
+    private Rect mWindowRect;
+
+    private Rect mTaskGridRect;
+
+    public TaskGridLayoutAlgorithm(Context context) {
+        reloadOnConfigurationChange(context);
+    }
+
+    public void reloadOnConfigurationChange(Context context) {
+        Resources res = context.getResources();
+        mPaddingLeftRight = res.getDimensionPixelSize(R.dimen.recents_grid_padding_left_right);
+        mPaddingTopBottom = res.getDimensionPixelSize(R.dimen.recents_grid_padding_top_bottom);
+        mPaddingTaskView = res.getDimensionPixelSize(R.dimen.recents_grid_padding_task_view);
+
+        mTaskGridRect = new Rect();
+    }
+
+    public TaskViewTransform getTransform(int taskIndex, int taskAmount,
+        TaskViewTransform transformOut, TaskStackLayoutAlgorithm stackLayout) {
+
+        int taskPerLine = taskAmount < 2 ? 1 : (
+            taskAmount < 5 ? 2 : 3);
+
+        int taskWidth = (mDisplayRect.width() - mPaddingLeftRight * 2
+            - mPaddingTaskView * (taskPerLine - 1)) / taskPerLine;
+        int taskHeight = taskWidth * mDisplayRect.height() / mDisplayRect.width();
+        mTaskGridRect.set(0, 0, taskWidth, taskHeight);
+
+        int xIndex = taskIndex % taskPerLine;
+        int yIndex = taskIndex / taskPerLine;
+        int x = mPaddingLeftRight + (taskWidth + mPaddingTaskView) * xIndex;
+        int y = mPaddingTopBottom + (taskHeight + mPaddingTaskView) * yIndex;
+        float z = stackLayout.mMaxTranslationZ;
+
+        float dimAlpha = 0f;
+        float viewOutlineAlpha = 0f;
+
+        // Fill out the transform
+        transformOut.scale = 1f;
+        transformOut.alpha = 1f;
+        transformOut.translationZ = z;
+        transformOut.dimAlpha = dimAlpha;
+        transformOut.viewOutlineAlpha = viewOutlineAlpha;
+        transformOut.rect.set(mTaskGridRect);
+        transformOut.rect.offset(x, y);
+        Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
+        transformOut.visible = true;
+        return transformOut;
+    }
+
+    public void initialize(Rect displayRect, Rect windowRect) {
+        mDisplayRect = displayRect;
+        mWindowRect = windowRect;
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
index 3db03d0..cb9453b 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.graphics.PixelFormat;
+import android.os.Binder;
 import android.view.View;
 import android.view.WindowManager;
 
@@ -51,6 +52,7 @@
                 FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL
                         | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY,
                 PixelFormat.TRANSLUCENT);
+        mLp.token = new Binder();
         mLp.setTitle(WINDOW_TITLE);
         mLp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION;
         view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
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 ae9d068..5da652d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -74,6 +74,7 @@
 import android.media.session.PlaybackState;
 import android.net.Uri;
 import android.os.AsyncTask;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -1531,6 +1532,7 @@
                     | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
                     | WindowManager.LayoutParams.FLAG_SLIPPERY,
                 PixelFormat.TRANSLUCENT);
+        lp.token = new Binder();
         // this will allow the navbar to run in an overlay on devices that support this
         if (ActivityManager.isHighEndGfx()) {
             lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
@@ -2966,7 +2968,7 @@
 
         runPostCollapseRunnables();
         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
-        showBouncer();
+        showBouncerIfKeyguard();
         recomputeDisableFlags(shouldAnimatIconHiding() /* animate */);
 
         // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
@@ -4540,13 +4542,17 @@
         return false;
     }
 
-    protected void showBouncer() {
+    private void showBouncerIfKeyguard() {
         if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
-            mWaitingForKeyguardExit = mStatusBarKeyguardViewManager.isShowing();
-            mStatusBarKeyguardViewManager.dismiss();
+            showBouncer();
         }
     }
 
+    protected void showBouncer() {
+        mWaitingForKeyguardExit = mStatusBarKeyguardViewManager.isShowing();
+        mStatusBarKeyguardViewManager.dismiss();
+    }
+
     private void instantExpandNotificationsPanel() {
 
         // Make our window larger and the panel expanded.
@@ -4644,7 +4650,7 @@
     public void onTrackingStopped(boolean expand) {
         if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
             if (!expand && !mUnlockMethodCache.canSkipBouncer()) {
-                showBouncer();
+                showBouncerIfKeyguard();
             }
         }
     }
@@ -4739,7 +4745,7 @@
                 || !mShowLockscreenNotifications || mFalsingManager.shouldEnforceBouncer();
         if (isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) {
             mLeaveOpenOnKeyguardHide = true;
-            showBouncer();
+            showBouncerIfKeyguard();
             mDraggedDownRow = row;
             mPendingRemoteInputView = null;
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index 29c0705..0660054 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -22,6 +22,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
+import android.os.Binder;
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.Trace;
@@ -97,6 +98,7 @@
                         | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                         | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
                 PixelFormat.TRANSLUCENT);
+        mLp.token = new Binder();
         mLp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
         mLp.gravity = Gravity.TOP;
         mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/SpTexts.java b/packages/SystemUI/src/com/android/systemui/volume/ConfigurableTexts.java
similarity index 74%
rename from packages/SystemUI/src/com/android/systemui/volume/SpTexts.java
rename to packages/SystemUI/src/com/android/systemui/volume/ConfigurableTexts.java
index d8e53db..20de5bb 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/SpTexts.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ConfigurableTexts.java
@@ -25,19 +25,23 @@
 import android.widget.TextView;
 
 /**
- * Capture initial sp values for registered textviews, and update properly when configuration
- * changes.
+ * Class for updating textviews on configuration change.
  */
-public class SpTexts {
+public class ConfigurableTexts {
 
     private final Context mContext;
     private final ArrayMap<TextView, Integer> mTexts = new ArrayMap<>();
+    private final ArrayMap<TextView, Integer> mTextLabels = new ArrayMap<>();
 
-    public SpTexts(Context context) {
+    public ConfigurableTexts(Context context) {
         mContext = context;
     }
 
     public int add(final TextView text) {
+        return add(text, -1);
+    }
+
+    public int add(final TextView text, final int labelResId) {
         if (text == null) return 0;
         final Resources res = mContext.getResources();
         final float fontScale = res.getConfiguration().fontScale;
@@ -55,6 +59,7 @@
                setTextSizeH(text, sp);
             }
         });
+        mTextLabels.put(text, labelResId);
         return sp;
     }
 
@@ -67,12 +72,25 @@
         text.setTextSize(TypedValue.COMPLEX_UNIT_SP, sp);
     }
 
+    private void setTextLabelH(TextView text, int labelResId) {
+        try {
+            if (labelResId >= 0) {
+                Util.setText(text, mContext.getString(labelResId));
+            }
+        } catch (Resources.NotFoundException e) {
+            // oh well.
+        }
+    }
+
     private final Runnable mUpdateAll = new Runnable() {
         @Override
         public void run() {
             for (int i = 0; i < mTexts.size(); i++) {
                 setTextSizeH(mTexts.keyAt(i), mTexts.valueAt(i));
             }
+            for (int i = 0; i < mTextLabels.size(); i++) {
+                setTextLabelH(mTextLabels.keyAt(i), mTextLabels.valueAt(i));
+            }
         }
     };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
index c6e4356..89bc757 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
@@ -36,7 +36,7 @@
 
     private final Context mContext;
     protected final LayoutInflater mInflater;
-    private final SpTexts mSpTexts;
+    private final ConfigurableTexts mConfigurableTexts;
 
     private Callback mCallback;
     protected Object mSelectedValue;
@@ -46,7 +46,7 @@
         mContext = context;
         mInflater = LayoutInflater.from(mContext);
         setOrientation(HORIZONTAL);
-        mSpTexts = new SpTexts(mContext);
+        mConfigurableTexts = new ConfigurableTexts(mContext);
     }
 
     public void setCallback(Callback callback) {
@@ -97,15 +97,11 @@
                 fireInteraction();
             }
         });
-        mSpTexts.add(b);
+        mConfigurableTexts.add(b, labelResId);
     }
 
-    public void updateLocale() {
-        for (int i = 0; i < getChildCount(); i++) {
-            final Button b = (Button) getChildAt(i);
-            final int labelResId = (Integer) b.getTag(LABEL_RES_KEY);
-            b.setText(labelResId);
-        }
+    public void update() {
+        mConfigurableTexts.update();
     }
 
     private void fireOnSelected(boolean fromClick) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 42b06b2..d23ebc1 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -46,6 +46,7 @@
 import android.transition.TransitionManager;
 import android.util.DisplayMetrics;
 import android.util.Log;
+import android.util.Slog;
 import android.util.SparseBooleanArray;
 import android.view.Gravity;
 import android.view.MotionEvent;
@@ -109,7 +110,7 @@
     private ViewGroup mDialogContentView;
     private ImageButton mExpandButton;
     private final List<VolumeRow> mRows = new ArrayList<>();
-    private SpTexts mSpTexts;
+    private ConfigurableTexts mConfigurableTexts;
     private final SparseBooleanArray mDynamic = new SparseBooleanArray();
     private final KeyguardManager mKeyguard;
     private final AudioManager mAudioManager;
@@ -128,7 +129,6 @@
     private boolean mExpanded;
 
     private int mActiveStream;
-    private boolean mShowHeaders = VolumePrefs.DEFAULT_SHOW_HEADERS;
     private boolean mAutomute = VolumePrefs.DEFAULT_ENABLE_AUTOMUTE;
     private boolean mSilentMode = VolumePrefs.DEFAULT_ENABLE_SILENT_MODE;
     private State mState;
@@ -173,7 +173,7 @@
     private void initDialog() {
         mDialog = new CustomDialog(mContext);
 
-        mSpTexts = new SpTexts(mContext);
+        mConfigurableTexts = new ConfigurableTexts(mContext);
         mHovering = false;
         mShowing = false;
         mWindow = mDialog.getWindow();
@@ -294,12 +294,6 @@
         mHandler.obtainMessage(H.SET_STREAM_IMPORTANT, stream, important ? 1 : 0).sendToTarget();
     }
 
-    public void setShowHeaders(boolean showHeaders) {
-        if (showHeaders == mShowHeaders) return;
-        mShowHeaders = showHeaders;
-        mHandler.sendEmptyMessage(H.RECHECK_ALL);
-    }
-
     public void setAutomute(boolean automute) {
         if (mAutomute == automute) return;
         mAutomute = automute;
@@ -357,7 +351,6 @@
         writer.println(mExpandButtonAnimationRunning);
         writer.print("  mActiveStream: "); writer.println(mActiveStream);
         writer.print("  mDynamic: "); writer.println(mDynamic);
-        writer.print("  mShowHeaders: "); writer.println(mShowHeaders);
         writer.print("  mAutomute: "); writer.println(mAutomute);
         writer.print("  mSilentMode: "); writer.println(mSilentMode);
         writer.print("  mCollapseTime: "); writer.println(mCollapseTime);
@@ -385,11 +378,9 @@
         row.view.setTag(row);
         row.header = (TextView) row.view.findViewById(R.id.volume_row_header);
         row.header.setId(20 * row.stream);
-        mSpTexts.add(row.header);
         row.slider = (SeekBar) row.view.findViewById(R.id.volume_row_slider);
         row.slider.setOnSeekBarChangeListener(new VolumeSeekBarChangeListener(row));
         row.anim = null;
-        row.cachedShowHeaders = VolumePrefs.DEFAULT_SHOW_HEADERS;
 
         // forward events above the slider into the slider
         row.view.setOnTouchListener(new OnTouchListener() {
@@ -617,8 +608,8 @@
             final boolean isActive = row == activeRow;
             final boolean shouldBeVisible = shouldBeVisibleH(row, isActive);
             Util.setVisOrGone(row.view, shouldBeVisible);
+            Util.setVisOrGone(row.header, shouldBeVisible);
             if (row.view.isShown()) {
-                updateVolumeRowHeaderVisibleH(row);
                 updateVolumeRowSliderTintH(row, isActive);
             }
         }
@@ -731,11 +722,9 @@
             row.slider.setMax(max);
         }
 
-        // update header visible
-        updateVolumeRowHeaderVisibleH(row);
-
         // update header text
-        Util.setText(row.header, ss.name);
+        Util.setText(row.header, getStreamLabelH(ss));
+        mConfigurableTexts.add(row.header, ss.name);
 
         // update icon
         final boolean iconEnabled = (mAutomute || ss.muteSupported) && !zenMuted;
@@ -768,31 +757,31 @@
                 if (isRingVibrate) {
                     row.icon.setContentDescription(mContext.getString(
                             R.string.volume_stream_content_description_unmute,
-                            ss.name));
+                            getStreamLabelH(ss)));
                 } else {
                     if (mController.hasVibrator()) {
                         row.icon.setContentDescription(mContext.getString(
                                 R.string.volume_stream_content_description_vibrate,
-                                ss.name));
+                                getStreamLabelH(ss)));
                     } else {
                         row.icon.setContentDescription(mContext.getString(
                                 R.string.volume_stream_content_description_mute,
-                                ss.name));
+                                getStreamLabelH(ss)));
                     }
                 }
             } else {
                 if (ss.muted || mAutomute && ss.level == 0) {
                    row.icon.setContentDescription(mContext.getString(
                            R.string.volume_stream_content_description_unmute,
-                           ss.name));
+                           getStreamLabelH(ss)));
                 } else {
                     row.icon.setContentDescription(mContext.getString(
                             R.string.volume_stream_content_description_mute,
-                            ss.name));
+                            getStreamLabelH(ss)));
                 }
             }
         } else {
-            row.icon.setContentDescription(ss.name);
+            row.icon.setContentDescription(getStreamLabelH(ss));
         }
 
         // update slider
@@ -802,15 +791,6 @@
         updateVolumeRowSliderH(row, enableSlider, vlevel);
     }
 
-    private void updateVolumeRowHeaderVisibleH(VolumeRow row) {
-        final boolean dynamic = row.ss != null && row.ss.dynamic;
-        final boolean showHeaders = mExpanded && (mShowHeaders || dynamic);
-        if (row.cachedShowHeaders != showHeaders) {
-            row.cachedShowHeaders = showHeaders;
-            Util.setVisOrGone(row.header, showHeaders);
-        }
-    }
-
     private void updateVolumeRowSliderTintH(VolumeRow row, boolean isActive) {
         if (isActive && mExpanded) {
             row.slider.requestFocus();
@@ -920,6 +900,18 @@
         rescheduleTimeoutH();
     }
 
+    private String getStreamLabelH(StreamState ss) {
+        if (ss.remoteLabel != null) {
+            return ss.remoteLabel;
+        }
+        try {
+            return mContext.getString(ss.name);
+        } catch (Resources.NotFoundException e) {
+            Slog.e(TAG, "Can't find translation for stream " + ss);
+            return "";
+        }
+    }
+
     private AutoTransition getTransistion() {
         AutoTransition transition = new AutoTransition();
         transition.setDuration(mExpandButtonAnimationDuration);
@@ -995,7 +987,7 @@
                 mDensity = density;
             }
             updateWindowWidthH();
-            mSpTexts.update();
+            mConfigurableTexts.update();
             mZenFooter.onConfigurationChanged();
         }
 
@@ -1125,7 +1117,7 @@
                 if (mShowing) {
                     event.getText().add(mContext.getString(
                             R.string.volume_dialog_accessibility_shown_message,
-                            getActiveRow().ss.name));
+                            getStreamLabelH(getActiveRow().ss)));
                     return true;
                 }
             }
@@ -1253,7 +1245,6 @@
         private int cachedIconRes;
         private ColorStateList cachedSliderTint;
         private int iconState;  // from Events
-        private boolean cachedShowHeaders = VolumePrefs.DEFAULT_SHOW_HEADERS;
         private ObjectAnimator anim;  // slider progress animation for non-touch-related updates
         private int animTargetProgress;
         private int lastAudibleLevel = 1;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
index bb5632b..17dd8d6 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.volume;
 
+import android.annotation.IntegerRes;
 import android.app.NotificationManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -41,6 +42,7 @@
 import android.os.Vibrator;
 import android.provider.Settings;
 import android.service.notification.Condition;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.util.SparseArray;
 
@@ -67,19 +69,20 @@
     private static final int DYNAMIC_STREAM_START_INDEX = 100;
     private static final int VIBRATE_HINT_DURATION = 50;
 
-    private static final int[] STREAMS = {
-        AudioSystem.STREAM_ALARM,
-        AudioSystem.STREAM_BLUETOOTH_SCO,
-        AudioSystem.STREAM_DTMF,
-        AudioSystem.STREAM_MUSIC,
-        AudioSystem.STREAM_NOTIFICATION,
-        AudioSystem.STREAM_RING,
-        AudioSystem.STREAM_SYSTEM,
-        AudioSystem.STREAM_SYSTEM_ENFORCED,
-        AudioSystem.STREAM_TTS,
-        AudioSystem.STREAM_VOICE_CALL,
-        AudioSystem.STREAM_ACCESSIBILITY,
-    };
+    private static final ArrayMap<Integer, Integer> STREAMS = new ArrayMap<>();
+    static {
+        STREAMS.put(AudioSystem.STREAM_ALARM, R.string.stream_alarm);
+        STREAMS.put(AudioSystem.STREAM_BLUETOOTH_SCO, R.string.stream_bluetooth_sco);
+        STREAMS.put(AudioSystem.STREAM_DTMF, R.string.stream_dtmf);
+        STREAMS.put(AudioSystem.STREAM_MUSIC, R.string.stream_music);
+        STREAMS.put(AudioSystem.STREAM_NOTIFICATION, R.string.stream_notification);
+        STREAMS.put(AudioSystem.STREAM_RING, R.string.stream_ring);
+        STREAMS.put(AudioSystem.STREAM_SYSTEM, R.string.stream_system);
+        STREAMS.put(AudioSystem.STREAM_SYSTEM_ENFORCED, R.string.stream_system_enforced);
+        STREAMS.put(AudioSystem.STREAM_TTS, R.string.stream_tts);
+        STREAMS.put(AudioSystem.STREAM_VOICE_CALL, R.string.stream_voice_call);
+        STREAMS.put(AudioSystem.STREAM_ACCESSIBILITY, R.string.stream_accessibility);
+    }
 
     private final HandlerThread mWorkerThread;
     private final W mWorker;
@@ -92,7 +95,6 @@
     private final MediaSessions mMediaSessions;
     private final C mCallbacks = new C();
     private final State mState = new State();
-    private final String[] mStreamTitles;
     private final MediaSessionsCallbacks mMediaSessionsCallbacksW = new MediaSessionsCallbacks();
     private final Vibrator mVibrator;
     private final boolean mHasVibrator;
@@ -120,26 +122,6 @@
         mObserver = new SettingObserver(mWorker);
         mObserver.init();
         mReceiver.init();
-        final String[] titles =
-                mContext.getResources().getStringArray(R.array.volume_stream_titles);
-        if (STREAMS.length == titles.length) {
-            mStreamTitles = titles;
-        } else if (STREAMS.length > titles.length) {
-            Log.e(TAG, String.format("Missing stream titles (found %d, expected %d): "
-                    + " invalid resources for volume_stream_titles",
-                    titles.length, STREAMS.length));
-            mStreamTitles = new String[STREAMS.length];
-            System.arraycopy(titles, 0, mStreamTitles, 0, titles.length);
-            for (int i = titles.length ; i < STREAMS.length ; i++) {
-                mStreamTitles[i] = "";
-            }
-        } else { // STREAMS.length < titles.length
-            Log.e(TAG, String.format("Too many stream titles (found %d, expected %d): "
-                    + " invalid resources for volume_stream_titles",
-                    titles.length, STREAMS.length));
-            mStreamTitles = new String[STREAMS.length];
-            System.arraycopy(titles, 0, mStreamTitles, 0, STREAMS.length);
-        }
         mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
         mHasVibrator = mVibrator != null && mVibrator.hasVibrator();
     }
@@ -385,14 +367,14 @@
     }
 
     private void onGetStateW() {
-        for (int stream : STREAMS) {
+        for (int stream : STREAMS.keySet()) {
             updateStreamLevelW(stream, getAudioManagerStreamVolume(stream));
             streamStateW(stream).levelMin = getAudioManagerStreamMinVolume(stream);
             streamStateW(stream).levelMax = getAudioManagerStreamMaxVolume(stream);
             updateStreamMuteW(stream, mAudio.isStreamMute(stream));
             final StreamState ss = streamStateW(stream);
             ss.muteSupported = mAudio.isStreamAffectedByMute(stream);
-            ss.name = mStreamTitles[stream];
+            ss.name = STREAMS.get(stream);
             checkRoutedToBluetoothW(stream);
         }
         updateRingerModeExternalW(mAudio.getRingerMode());
@@ -912,8 +894,9 @@
                 ss.level = pi.getCurrentVolume();
                 changed = true;
             }
-            if (!Objects.equals(ss.name, name)) {
-                ss.name = name;
+            if (!Objects.equals(ss.remoteLabel, name)) {
+                ss.name = -1;
+                ss.remoteLabel = name;
                 changed = true;
             }
             if (changed) {
@@ -975,7 +958,8 @@
         public int levelMax;
         public boolean muted;
         public boolean muteSupported;
-        public String name;
+        public @IntegerRes int name;
+        public String remoteLabel;
         public boolean routedToBluetooth;
 
         public StreamState copy() {
@@ -987,6 +971,7 @@
             rt.muted = muted;
             rt.muteSupported = muteSupported;
             rt.name = name;
+            rt.remoteLabel = remoteLabel;
             rt.routedToBluetooth = routedToBluetooth;
             return rt;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
index 995ecae..4e4832c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
@@ -38,7 +38,7 @@
     private static final String TAG = Util.logTag(ZenFooter.class);
 
     private final Context mContext;
-    private final SpTexts mSpTexts;
+    private final ConfigurableTexts mConfigurableTexts;
 
     private ImageView mIcon;
     private TextView mSummaryLine1;
@@ -51,7 +51,7 @@
     public ZenFooter(Context context, AttributeSet attrs) {
         super(context, attrs);
         mContext = context;
-        mSpTexts = new SpTexts(mContext);
+        mConfigurableTexts = new ConfigurableTexts(mContext);
         final LayoutTransition layoutTransition = new LayoutTransition();
         layoutTransition.setDuration(new ValueAnimator().getDuration() / 2);
         setLayoutTransition(layoutTransition);
@@ -64,9 +64,9 @@
         mSummaryLine1 = (TextView) findViewById(R.id.volume_zen_summary_line_1);
         mSummaryLine2 = (TextView) findViewById(R.id.volume_zen_summary_line_2);
         mEndNowButton = (TextView) findViewById(R.id.volume_zen_end_now);
-        mSpTexts.add(mSummaryLine1);
-        mSpTexts.add(mSummaryLine2);
-        mSpTexts.add(mEndNowButton);
+        mConfigurableTexts.add(mSummaryLine1);
+        mConfigurableTexts.add(mSummaryLine2);
+        mConfigurableTexts.add(mEndNowButton, R.string.volume_zen_end_now);
     }
 
     public void init(final ZenModeController controller) {
@@ -130,8 +130,7 @@
     }
 
     public void onConfigurationChanged() {
-        Util.setText(mEndNowButton, mContext.getString(R.string.volume_zen_end_now));
-        mSpTexts.update();
+        mConfigurableTexts.update();
     }
 
     private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index 12a00e9..98e89e4 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -92,7 +92,7 @@
     private final ZenPrefs mPrefs;
     private final TransitionHelper mTransitionHelper = new TransitionHelper();
     private final Uri mForeverId;
-    private final SpTexts mSpTexts;
+    private final ConfigurableTexts mConfigurableTexts;
 
     private String mTag = TAG + "/" + Integer.toHexString(System.identityHashCode(this));
 
@@ -131,7 +131,7 @@
         mPrefs = new ZenPrefs();
         mInflater = LayoutInflater.from(mContext.getApplicationContext());
         mForeverId = Condition.newId(mContext).appendPath("forever").build();
-        mSpTexts = new SpTexts(mContext);
+        mConfigurableTexts = new ConfigurableTexts(mContext);
         mVoiceCapable = Util.isVoiceCapable(mContext);
         mZenModeConditionLayoutId = R.layout.zen_mode_condition;
         mZenModeButtonLayoutId = R.layout.zen_mode_button;
@@ -175,7 +175,6 @@
         createZenButtons();
         mZenIntroduction = findViewById(R.id.zen_introduction);
         mZenIntroductionMessage = (TextView) findViewById(R.id.zen_introduction_message);
-        mSpTexts.add(mZenIntroductionMessage);
         mZenIntroductionConfirm = findViewById(R.id.zen_introduction_confirm);
         mZenIntroductionConfirm.setOnClickListener(new OnClickListener() {
             @Override
@@ -193,7 +192,7 @@
                 }
             }
         });
-        mSpTexts.add(mZenIntroductionCustomize);
+        mConfigurableTexts.add(mZenIntroductionCustomize, R.string.zen_priority_customize_button);
 
         mZenConditions = (LinearLayout) findViewById(R.id.zen_conditions);
         mZenAlarmWarning = (TextView) findViewById(R.id.zen_alarm_warning);
@@ -204,11 +203,9 @@
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
+        mConfigurableTexts.update();
         if (mZenButtons != null) {
-            mZenButtons.updateLocale();
-        }
-        if (mZenIntroductionCustomize != null) {
-            mZenIntroductionCustomize.setText(R.string.zen_priority_customize_button);
+            mZenButtons.update();
         }
     }
 
@@ -341,10 +338,6 @@
         hideAllConditions();
     }
 
-    public void updateLocale() {
-        mZenButtons.updateLocale();
-    }
-
     private void setExitCondition(Condition exitCondition) {
         if (Objects.equals(mExitCondition, exitCondition)) return;
         mExitCondition = exitCondition;
@@ -439,9 +432,11 @@
         mZenButtons.setVisibility(mHidden ? GONE : VISIBLE);
         mZenIntroduction.setVisibility(introduction ? VISIBLE : GONE);
         if (introduction) {
-            mZenIntroductionMessage.setText(zenImportant ? R.string.zen_priority_introduction
+            mConfigurableTexts.add(mZenIntroductionMessage, zenImportant
+                    ? R.string.zen_priority_introduction
                     : mVoiceCapable ? R.string.zen_silence_introduction_voice
                     : R.string.zen_silence_introduction);
+            mConfigurableTexts.update();
             mZenIntroductionCustomize.setVisibility(zenImportant ? VISIBLE : GONE);
         }
         final String warning = computeAlarmWarningText(zenNone);
@@ -655,11 +650,11 @@
         }
         if (tag.line1 == null) {
             tag.line1 = (TextView) row.findViewById(android.R.id.text1);
-            mSpTexts.add(tag.line1);
+            mConfigurableTexts.add(tag.line1);
         }
         if (tag.line2 == null) {
             tag.line2 = (TextView) row.findViewById(android.R.id.text2);
-            mSpTexts.add(tag.line2);
+            mConfigurableTexts.add(tag.line2);
         }
         final String line1 = !TextUtils.isEmpty(condition.line1) ? condition.line1
                 : condition.summary;
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index ecf174f..e96ea19 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -44,7 +44,7 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     android-support-test \
-    mockito-target-minus-junit4 \
+    mockito-updated-target-minus-junit4 \
     SystemUI-proto \
     SystemUI-tags
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 008580a..d1d7520 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -37,6 +37,7 @@
 
     @Before
     public void SysuiSetup() throws Exception {
+        System.setProperty("dexmaker.share_classloader", "true");
         mContext = new TestableContext(InstrumentationRegistry.getTargetContext(), this);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
index 8b99d72..c3948258 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -214,6 +214,16 @@
 
     @Test
     @UiThreadTest
+    public void testSuppressingPulse_doesntCrash() {
+        mMachine.requestState(INITIALIZED);
+
+        mMachine.requestState(DOZE);
+        mMachine.requestState(DOZE_REQUEST_PULSE);
+        mMachine.requestState(DOZE_PULSE_DONE);
+    }
+
+    @Test
+    @UiThreadTest
     public void testScreen_offInDoze() {
         mMachine.requestState(INITIALIZED);
 
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 136e7c0..6fe7768 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
@@ -49,6 +49,11 @@
 import java.util.List;
 
 import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -282,14 +287,11 @@
         ArgumentCaptor<Boolean> dataOutArg = ArgumentCaptor.forClass(Boolean.class);
 
         Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators(
-                    ArgumentCaptor.forClass(IconState.class).capture(),
+                    any(),
                     iconArg.capture(),
-                    ArgumentCaptor.forClass(Integer.class).capture(),
+                    anyInt(),
                     typeIconArg.capture(), dataInArg.capture(), dataOutArg.capture(),
-                    ArgumentCaptor.forClass(String.class).capture(),
-                    ArgumentCaptor.forClass(String.class).capture(),
-                    ArgumentCaptor.forClass(Boolean.class).capture(),
-                    ArgumentCaptor.forClass(Integer.class).capture());
+                    anyString(), anyString(), anyBoolean(), anyInt());
         IconState iconState = iconArg.getValue();
         assertEquals("Visibility in, quick settings", visible, iconState.visible);
         assertEquals("Signal icon in, quick settings", icon, iconState.icon);
@@ -307,21 +309,50 @@
         // TODO: Verify all fields.
         Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators(
                 iconArg.capture(),
-                ArgumentCaptor.forClass(IconState.class).capture(),
+                any(),
                 typeIconArg.capture(),
-                ArgumentCaptor.forClass(Integer.class).capture(),
-                ArgumentCaptor.forClass(Boolean.class).capture(),
-                ArgumentCaptor.forClass(Boolean.class).capture(),
-                ArgumentCaptor.forClass(String.class).capture(),
-                ArgumentCaptor.forClass(String.class).capture(),
-                ArgumentCaptor.forClass(Boolean.class).capture(),
-                ArgumentCaptor.forClass(Integer.class).capture());
+                anyInt(), anyBoolean(), anyBoolean(), anyString(), anyString(), anyBoolean(),
+                anyInt());
         IconState iconState = iconArg.getValue();
 
         assertEquals("Data icon in status bar", typeIcon, (int) typeIconArg.getValue());
         assertEquals("Visibility in status bar", visible, iconState.visible);
     }
 
+    protected void verifyLastMobileDataIndicators(boolean visible, int icon, int typeIcon,
+            boolean qsVisible, int qsIcon, int qsTypeIcon, boolean dataIn, boolean dataOut) {
+        ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
+        ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class);
+        ArgumentCaptor<IconState> qsIconArg = ArgumentCaptor.forClass(IconState.class);
+        ArgumentCaptor<Integer> qsTypeIconArg = ArgumentCaptor.forClass(Integer.class);
+        ArgumentCaptor<Boolean> dataInArg = ArgumentCaptor.forClass(Boolean.class);
+        ArgumentCaptor<Boolean> dataOutArg = ArgumentCaptor.forClass(Boolean.class);
+
+        Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators(
+                iconArg.capture(),
+                qsIconArg.capture(),
+                typeIconArg.capture(),
+                qsTypeIconArg.capture(),
+                dataInArg.capture(),
+                dataOutArg.capture(),
+                anyString(), anyString(), anyBoolean(), anyInt());
+
+        IconState iconState = iconArg.getValue();
+
+        assertEquals("Data icon in status bar", typeIcon, (int) typeIconArg.getValue());
+        assertEquals("Signal icon in status bar", icon, iconState.icon);
+        assertEquals("Visibility in status bar", visible, iconState.visible);
+
+        iconState = qsIconArg.getValue();
+        assertEquals("Visibility in quick settings", qsVisible, iconState.visible);
+        assertEquals("Signal icon in quick settings", qsIcon, iconState.icon);
+        assertEquals("Data icon in quick settings", qsTypeIcon, (int) qsTypeIconArg.getValue());
+        assertEquals("Data direction in in quick settings", dataIn,
+                (boolean) dataInArg.getValue());
+        assertEquals("Data direction out in quick settings", dataOut,
+                (boolean) dataOutArg.getValue());
+    }
+
    protected void assertNetworkNameEquals(String expected) {
        assertEquals("Network name", expected, mMobileSignalController.getState().networkName);
    }
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 55ec572..4f961ab 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
@@ -29,8 +29,8 @@
 
         verifyLastMobileDataIndicators(true,
                 TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[1][DEFAULT_LEVEL],
-                TelephonyIcons.ROAMING_ICON);
-        verifyLastQsMobileDataIndicators(true,
+                TelephonyIcons.ROAMING_ICON,
+                true,
                 TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][DEFAULT_LEVEL],
                 TelephonyIcons.QS_DATA_R, false, false);
     }
@@ -183,14 +183,13 @@
     private void testDataActivity(int direction, boolean in, boolean out) {
         updateDataActivity(direction);
 
-        verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, DEFAULT_ICON);
-        verifyLastQsMobileDataIndicators(true, DEFAULT_QS_SIGNAL_STRENGTH,
-                DEFAULT_QS_ICON, in, out);
+        verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, DEFAULT_ICON, true,
+                DEFAULT_QS_SIGNAL_STRENGTH, DEFAULT_QS_ICON, in, out);
     }
 
     private void verifyDataIndicators(int dataIcon, int qsDataIcon) {
-        verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, dataIcon);
-        verifyLastQsMobileDataIndicators(true, DEFAULT_QS_SIGNAL_STRENGTH, qsDataIcon, false,
+        verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, dataIcon,
+                true, DEFAULT_QS_SIGNAL_STRENGTH, qsDataIcon, false,
                 false);
     }
 
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 fc7f942..ed32f65 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
@@ -17,6 +17,9 @@
 
 import static junit.framework.Assert.assertEquals;
 
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class NetworkControllerWifiTest extends NetworkControllerBaseTest {
@@ -78,6 +81,9 @@
         verifyLastQsWifiIcon(true, true,
                 WifiIcons.QS_WIFI_SIGNAL_STRENGTH[1][testLevel], testSsid);
 
+        // Set to different activity state first to ensure a callback happens.
+        setWifiActivity(WifiManager.DATA_ACTIVITY_IN);
+
         setWifiActivity(WifiManager.DATA_ACTIVITY_NONE);
         verifyLastQsDataDirection(false, false);
         setWifiActivity(WifiManager.DATA_ACTIVITY_IN);
@@ -148,8 +154,7 @@
         ArgumentCaptor<Boolean> outArg = ArgumentCaptor.forClass(Boolean.class);
 
         Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators(
-                Mockito.anyBoolean(), Mockito.any(IconState.class), Mockito.any(IconState.class),
-                inArg.capture(), outArg.capture(), Mockito.anyString());
+                anyBoolean(), any(), any(), inArg.capture(), outArg.capture(), any());
         assertEquals("WiFi data in, in quick settings", in, (boolean) inArg.getValue());
         assertEquals("WiFi data out, in quick settings", out, (boolean) outArg.getValue());
     }
@@ -161,9 +166,7 @@
         ArgumentCaptor<String> descArg = ArgumentCaptor.forClass(String.class);
 
         Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators(
-                enabledArg.capture(), Mockito.any(IconState.class),
-                iconArg.capture(), Mockito.anyBoolean(),
-                Mockito.anyBoolean(),
+                enabledArg.capture(), any(), iconArg.capture(), anyBoolean(), anyBoolean(),
                 descArg.capture());
         IconState iconState = iconArg.getValue();
         assertEquals("WiFi enabled, in quick settings", enabled, (boolean) enabledArg.getValue());
@@ -176,8 +179,7 @@
         ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
 
         Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators(
-                Mockito.anyBoolean(), iconArg.capture(), Mockito.any(IconState.class),
-                Mockito.anyBoolean(), Mockito.anyBoolean(), Mockito.anyString());
+                anyBoolean(), iconArg.capture(), any(), anyBoolean(), anyBoolean(), any());
         IconState iconState = iconArg.getValue();
         assertEquals("WiFi visible, in status bar", visible, iconState.visible);
         assertEquals("WiFi signal, in status bar", icon, iconState.icon);
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index ef9d8f2..ec8c67b 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3105,6 +3105,26 @@
     // PACKAGE: The package name of the app the permission was revoked for
     ACTION_PERMISSION_REVOKE_READ_PHONE_NUMBER = 739;
 
+    // ACTION: A captive portal was detected during network validation
+    // CATEGORY: NOTIFICATION
+    // OS: N-MR2
+    NOTIFICATION_NETWORK_SIGN_IN = 740;
+
+    // ACTION: An unvalidated network without Internet was selected by the user
+    // CATEGORY: NOTIFICATION
+    // OS: N-MR2
+    NOTIFICATION_NETWORK_NO_INTERNET = 741;
+
+    // ACTION: A validated network failed revalidation and lost Internet access
+    // CATEGORY: NOTIFICATION
+    // OS: N-MR2
+    NOTIFICATION_NETWORK_LOST_INTERNET = 742;
+
+    // ACTION: The system default network switched to a different network
+    // CATEGORY: NOTIFICATION
+    // OS: N-MR2
+    NOTIFICATION_NETWORK_SWITCH = 743;
+
     // ---- End O Constants, all O constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index df71ced..386fbc9 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -560,7 +560,7 @@
 
     @Override
     public void interrupt(int userId) {
-        CopyOnWriteArrayList<Service> services;
+        List<IAccessibilityServiceClient> interfacesToInterrupt;
         synchronized (mLock) {
             // We treat calls from a profile as if made by its parent as profiles
             // share the accessibility state of the parent. The call below
@@ -571,15 +571,24 @@
             if (resolvedUserId != mCurrentUserId) {
                 return;
             }
-            services = getUserStateLocked(resolvedUserId).mBoundServices;
+            List<Service> services = getUserStateLocked(resolvedUserId).mBoundServices;
+            int numServices = services.size();
+            interfacesToInterrupt = new ArrayList<>(numServices);
+            for (int i = 0; i < numServices; i++) {
+                Service service = services.get(i);
+                IBinder a11yServiceBinder = service.mService;
+                IAccessibilityServiceClient a11yServiceInterface = service.mServiceInterface;
+                if ((a11yServiceBinder != null) && (a11yServiceInterface != null)) {
+                    interfacesToInterrupt.add(a11yServiceInterface);
+                }
+            }
         }
-        for (int i = 0, count = services.size(); i < count; i++) {
-            Service service = services.get(i);
+        for (int i = 0, count = interfacesToInterrupt.size(); i < count; i++) {
             try {
-                service.mServiceInterface.onInterrupt();
+                interfacesToInterrupt.get(i).onInterrupt();
             } catch (RemoteException re) {
-                Slog.e(LOG_TAG, "Error during sending interrupt request to "
-                    + service.mService, re);
+                Slog.e(LOG_TAG, "Error sending interrupt request to "
+                        + interfacesToInterrupt.get(i), re);
             }
         }
     }
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
index d70c439..6a16131 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
@@ -18,10 +18,13 @@
 
 import static android.Manifest.permission.MANAGE_AUTO_FILL;
 import static android.content.Context.AUTO_FILL_MANAGER_SERVICE;
+import static android.view.View.ASSIST_FLAG_SANITIZED_TEXT;
+import static android.view.View.ASSIST_FLAG_NON_SANITIZED_TEXT;
 
 import android.Manifest;
 import android.app.AppGlobals;
 import android.app.Notification;
+import android.app.Notification.Action;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -248,13 +251,14 @@
     final class AutoFillManagerServiceStub extends IAutoFillManagerService.Stub {
 
         @Override
-        public void requestAutoFill(int userId, IBinder activityToken) {
+        public void requestAutoFill(IBinder activityToken, int userId, int flags) {
+            if (DEBUG) Slog.d(TAG, "requestAutoFill: flags=" + flags + ", userId=" + userId);
             mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
 
             synchronized (mLock) {
                 final AutoFillManagerServiceImpl service = getServiceForUserLocked(userId);
                 if (service != null) {
-                    service.requestAutoFill(activityToken);
+                    service.requestAutoFill(activityToken, flags);
                 }
             }
         }
@@ -307,7 +311,7 @@
             synchronized (mLock) {
                 removeCachedServiceForUserLocked(userId);
                 final ComponentName serviceComponent = getProviderForUser(userId);
-                if (serviceComponent== null) {
+                if (serviceComponent == null) {
                     cancelNotificationLocked(userId);
                 } else {
                     showNotification(serviceComponent, userId);
@@ -322,9 +326,10 @@
     ////////////////////////////////////////////////////////////////////////////
 
     // TODO: remove from frameworks/base/core/res/AndroidManifest.xml once it's not used anymore
-    private static final String NOTIFICATION_INTENT =
+    private static final String NOTIFICATION_AUTO_FILL_INTENT =
             "com.android.internal.autofill.action.REQUEST_AUTOFILL";
     private static final String EXTRA_USER_ID = "user_id";
+    private static final String EXTRA_FLAGS = "flags";
 
     private static final int MSG_SHOW_ALL_NOTIFICATIONS = 42;
     private static final int SHOW_ALL_NOTIFICATIONS_DELAY_MS = 5000;
@@ -335,13 +340,14 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             final int userId = intent.getIntExtra(EXTRA_USER_ID, -1);
+            final int flags = intent.getIntExtra(EXTRA_FLAGS, 0);
             if (DEBUG) Slog.d(TAG, "Requesting autofill by notification for user " + userId);
             synchronized (mLock) {
                 final AutoFillManagerServiceImpl service = getServiceForUserLocked(userId);
                 if (service == null) {
                     Slog.w(TAG, "no auto-fill service for user " + userId);
                 } else {
-                    service.requestAutoFill(null);
+                    service.requestAutoFill(null, flags);
                 }
             }
         }
@@ -393,14 +399,23 @@
             if (mNotificationReceiver == null) {
                 mNotificationReceiver = new NotificationReceiver();
                 mContext.registerReceiver(mNotificationReceiver,
-                        new IntentFilter(NOTIFICATION_INTENT));
+                        new IntentFilter(NOTIFICATION_AUTO_FILL_INTENT));
             }
         }
 
-        final Intent intent = new Intent(NOTIFICATION_INTENT);
-        intent.putExtra(EXTRA_USER_ID, userId);
-        final PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent,
-                PendingIntent.FLAG_UPDATE_CURRENT);
+        final Intent fillIntent = new Intent(NOTIFICATION_AUTO_FILL_INTENT);
+        fillIntent.putExtra(EXTRA_USER_ID, userId);
+        fillIntent.putExtra(EXTRA_FLAGS, ASSIST_FLAG_SANITIZED_TEXT);
+        final PendingIntent fillPendingIntent = PendingIntent.getBroadcast(mContext,
+                ASSIST_FLAG_SANITIZED_TEXT, fillIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+        final Action fillAction = new Action.Builder(null, "FILL", fillPendingIntent).build();
+
+        final Intent saveIntent = new Intent(NOTIFICATION_AUTO_FILL_INTENT);
+        saveIntent.putExtra(EXTRA_USER_ID, userId);
+        saveIntent.putExtra(EXTRA_FLAGS, ASSIST_FLAG_NON_SANITIZED_TEXT);
+        final PendingIntent savePendingIntent = PendingIntent.getBroadcast(mContext,
+                ASSIST_FLAG_NON_SANITIZED_TEXT, saveIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+        final Action saveAction = new Action.Builder(null, "SAVE", savePendingIntent).build();
 
         final String packageName = serviceComponent.getPackageName();
         String providerName = null;
@@ -413,8 +428,8 @@
         } catch (Exception e) {
             providerName = packageName;
         }
-        final String title = "AutoFill by '" + providerName + "'";
-        final String subTitle = "Tap notification to auto-fill top activity for user " + userId;
+        final String title = "AutoFill actions";
+        final String subTitle = "Provider: " + providerName + "\n" + "User: " + userId;
 
         final Notification notification = new Notification.Builder(mContext)
                 .setCategory(Notification.CATEGORY_SYSTEM)
@@ -425,7 +440,7 @@
                         com.android.internal.R.color.system_notification_accent_color))
                 .setContentTitle(title)
                 .setStyle(new Notification.BigTextStyle().bigText(subTitle))
-                .setContentIntent(pi)
+                .setActions(fillAction, saveAction)
                 .build();
         NotificationManager.from(mContext).notify(userId, notification);
     }
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
index e409cb0..82356c8 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
@@ -47,7 +47,6 @@
 import com.android.server.LocalServices;
 
 import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
@@ -70,13 +69,13 @@
     private final AutoFillServiceInfo mInfo;
     private final AutoFillManagerService mManagerService;
 
-    // TODO: improve its usage
+    // TODO(b/33197203): improve its usage
     // - set maximum number of entries
     // - disable on low-memory devices.
     private final List<String> mRequestHistory = new LinkedList<>();
 
     @GuardedBy("mLock")
-    private final List<IBinder> mQueuedRequests = new LinkedList<>();
+    private final List<QueuedRequest> mQueuedRequests = new LinkedList<>();
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
@@ -84,7 +83,8 @@
             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
                 final String reason = intent.getStringExtra("reason");
                 if (DEBUG) Slog.d(TAG, "close system dialogs: " + reason);
-                // TODO: close any pending UI like account selection (or remove this receiver)
+                // TODO(b/33197203): close any pending UI like account selection (or remove this
+                // receiver)
             }
         }
     };
@@ -104,8 +104,8 @@
                 if (!mQueuedRequests.isEmpty()) {
                     if (DEBUG) Log.d(TAG, "queued requests:" + mQueuedRequests.size());
                 }
-                for (IBinder activityToken : mQueuedRequests) {
-                    requestAutoFillLocked(activityToken, false);
+                for (final QueuedRequest request: mQueuedRequests) {
+                    requestAutoFillLocked(request.activityToken, request.flags, false);
                 }
             }
         }
@@ -180,7 +180,7 @@
         if (DEBUG) Slog.d(TAG, "Bound to " + mComponent);
     }
 
-    void requestAutoFill(IBinder activityToken) {
+    void requestAutoFill(IBinder activityToken, int flags) {
         synchronized (mLock) {
             if (!mBound) {
                 Slog.w(TAG, "requestAutoFill() failed because it's not bound to service");
@@ -188,14 +188,14 @@
             }
         }
 
-        // TODO: activityToken should probably not be null, but we need to wait until the UI is
-        // triggering the call (for now it's trough 'adb shell cmd autofill request'
+        // TODO(b/33197203): activityToken should probably not be null, but we need to wait until
+        // the UI is triggering the call (for now it's trough 'adb shell cmd autofill request'
         if (activityToken == null) {
             // Let's get top activities from all visible stacks.
 
-            // TODO: overload getTopVisibleActivities() to take userId, otherwise it could return
-            // activities for different users when a work profile app is displayed in another
-            // window (in a multi-window environment).
+            // TODO(b/33197203): overload getTopVisibleActivities() to take userId, otherwise it
+            // could return activities for different users when a work profile app is displayed in
+            // another window (in a multi-window environment).
             final List<IBinder> topActivities = LocalServices
                     .getService(ActivityManagerInternal.class).getTopVisibleActivities();
             if (DEBUG)
@@ -211,32 +211,34 @@
                 DateFormat.getDateTimeInstance().format(new Date()) + " - " + activityToken;
         synchronized (mLock) {
             mRequestHistory.add(historyItem);
-            requestAutoFillLocked(activityToken, true);
+            requestAutoFillLocked(activityToken, flags, true);
         }
     }
 
-    private void requestAutoFillLocked(IBinder activityToken, boolean queueIfNecessary) {
+    private void requestAutoFillLocked(IBinder activityToken, int flags, boolean queueIfNecessary) {
         if (mService == null) {
             if (!queueIfNecessary) {
                 Slog.w(TAG, "requestAutoFillLocked(): service is null");
                 return;
             }
             if (DEBUG) Slog.d(TAG, "requestAutoFill(): service not set yet, queuing it");
-            mQueuedRequests.add(activityToken);
+            mQueuedRequests.add(new QueuedRequest(activityToken, flags));
             return;
         }
 
         /*
-         * TODO: apply security checks below:
+         * TODO(b/33197203): apply security checks below:
          * - checks if disabled by secure settings / device policy
          * - log operation using noteOp()
          * - check flags
          * - display disclosure if needed
          */
         try {
-            // TODO: add MetricsLogger call
-            if (!mAm.requestAutoFillData(mService.getAssistReceiver(), null, activityToken)) {
-                // TODO: might need a way to warn user (perhaps a new method on AutoFillService).
+            // TODO(b/33197203): add MetricsLogger call
+            if (!mAm.requestAutoFillData(mService.getAssistReceiver(), null, activityToken,
+                    flags)) {
+                // TODO(b/33197203): might need a way to warn user (perhaps a new method on
+                // AutoFillService).
                 Slog.w(TAG, "failed to request auto-fill data for " + activityToken);
             }
         } catch (RemoteException e) {
@@ -322,4 +324,19 @@
         return "[AutoFillManagerServiceImpl: userId=" + mUserId + ", uid=" + mUid
                 + ", component=" + mComponent.flattenToShortString() + "]";
     }
+
+    private static final class QueuedRequest {
+        final IBinder activityToken;
+        final int flags;
+
+        QueuedRequest(IBinder activityToken, int flags) {
+            this.activityToken = activityToken;
+            this.flags = flags;
+        }
+
+        @Override
+        public String toString() {
+            return "flags: " + flags + " token: " + activityToken;
+        }
+    }
 }
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
index 6406b8a..aa3503b 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
@@ -16,6 +16,9 @@
 
 package com.android.server.autofill;
 
+import static android.view.View.ASSIST_FLAG_SANITIZED_TEXT;
+import static android.view.View.ASSIST_FLAG_NON_SANITIZED_TEXT;
+
 import android.app.ActivityManager;
 import android.os.RemoteException;
 import android.os.ShellCommand;
@@ -40,8 +43,10 @@
         final PrintWriter pw = getOutPrintWriter();
         try {
             switch (cmd) {
-                case "request":
-                    return requestAutoFill();
+                case "fill":
+                    return requestAutoFill(ASSIST_FLAG_SANITIZED_TEXT);
+                case "save":
+                    return requestAutoFill(ASSIST_FLAG_NON_SANITIZED_TEXT);
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -58,15 +63,17 @@
             pw.println("  help");
             pw.println("    Prints this help text.");
             pw.println("");
-            pw.println("  request [--user USER_ID]");
-            pw.println("    Request auto-fill on the top activity. ");
+            pw.println("  fill [--user USER_ID]");
+            pw.println("    Request provider to auto-fill the top activity. ");
+            pw.println("  save [--user USER_ID]");
+            pw.println("    Request provider to save contents of the top activity. ");
             pw.println("");
         }
     }
 
-    private int requestAutoFill() throws RemoteException {
+    private int requestAutoFill(int flags) throws RemoteException {
         final int userId = getUserIdFromArgs();
-        mService.requestAutoFill(userId, null);
+        mService.requestAutoFill(null, userId, flags);
         return 0;
     }
 
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index b0c5603..d3110a4 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -105,6 +105,7 @@
     private static final int MESSAGE_USER_UNLOCKED = 301;
     private static final int MESSAGE_ADD_PROXY_DELAYED = 400;
     private static final int MESSAGE_BIND_PROFILE_SERVICE = 401;
+
     private static final int MAX_SAVE_RETRIES = 3;
     private static final int MAX_ERROR_RESTART_RETRIES = 6;
 
@@ -229,7 +230,8 @@
                     } finally {
                         mBluetoothLock.readLock().unlock();
                     }
-                    Slog.d(TAG, "Airplane Mode change - current state: " + st);
+                    Slog.d(TAG, "Airplane Mode change - current state: " +
+                              BluetoothAdapter.nameForState(st));
 
                     if (isAirplaneModeOn()) {
                         // Clear registered LE apps to force shut-off
@@ -426,6 +428,10 @@
     public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
                                                 "Need BLUETOOTH permission");
+        if (callback == null) {
+          Slog.w(TAG, "registerStateChangeCallback: Callback is null!");
+          return;
+        }
         Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
         msg.obj = callback;
         mHandler.sendMessage(msg);
@@ -434,6 +440,10 @@
     public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
                                                 "Need BLUETOOTH permission");
+        if (callback == null) {
+          Slog.w(TAG, "unregisterStateChangeCallback: Callback is null!");
+          return;
+        }
         Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
         msg.obj = callback;
         mHandler.sendMessage(msg);
@@ -460,7 +470,7 @@
     public int getState() {
         if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
                 (!checkIfCallerIsForegroundUser())) {
-            Slog.w(TAG, "getState(): not allowed for non-active and non system user");
+            Slog.w(TAG, "getState(): report OFF for non-active and non system user");
             return BluetoothAdapter.STATE_OFF;
         }
 
@@ -712,7 +722,8 @@
 
         if (DBG) {
             Slog.d(TAG,"enable():  mBluetooth =" + mBluetooth +
-                    " mBinding = " + mBinding + " mState = " + mState);
+                    " mBinding = " + mBinding + " mState = " +
+                    BluetoothAdapter.nameForState(mState));
         }
 
         synchronized(mReceiver) {
@@ -800,7 +811,7 @@
     public void unbindAndFinish() {
         if (DBG) {
             Slog.d(TAG,"unbindAndFinish(): " + mBluetooth +
-                " mBinding = " + mBinding);
+                " mBinding = " + mBinding + " mUnbinding = " + mUnbinding);
         }
 
         try {
@@ -816,16 +827,13 @@
                 } catch (RemoteException re) {
                     Slog.e(TAG, "Unable to unregister BluetoothCallback",re);
                 }
-
-                if (DBG) Slog.d(TAG, "Sending unbind request.");
                 mBluetoothBinder = null;
                 mBluetooth = null;
-                //Unbind
                 mContext.unbindService(mConnection);
                 mUnbinding = false;
                 mBinding = false;
             } else {
-                mUnbinding=false;
+                mUnbinding = false;
             }
             mBluetoothGatt = null;
         } finally {
@@ -1101,7 +1109,6 @@
      * Inform BluetoothAdapter instances that Adapter service is up
      */
     private void sendBluetoothServiceUpCallback() {
-        if (DBG) Slog.d(TAG,"Calling onBluetoothServiceUp callbacks");
         try {
             int n = mCallbacks.beginBroadcast();
             Slog.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
@@ -1120,7 +1127,6 @@
      * Inform BluetoothAdapter instances that Adapter service is down
      */
     private void sendBluetoothServiceDownCallback() {
-        if (DBG) Slog.d(TAG,"Calling onBluetoothServiceDown callbacks");
         try {
             int n = mCallbacks.beginBroadcast();
             Slog.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
@@ -1192,34 +1198,33 @@
     }
 
     private class BluetoothServiceConnection implements ServiceConnection {
-        public void onServiceConnected(ComponentName className, IBinder service) {
-            if (DBG) Slog.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
+        public void onServiceConnected(ComponentName componentName, IBinder service) {
+            String name = componentName.getClassName();
+            if (DBG) Slog.d(TAG, "BluetoothServiceConnection: " + name);
             Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
-            // TBD if (className.getClassName().equals(IBluetooth.class.getName())) {
-            if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
+            if (name.equals("com.android.bluetooth.btservice.AdapterService")) {
                 msg.arg1 = SERVICE_IBLUETOOTH;
-                // } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) {
-            } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
+            } else if (name.equals("com.android.bluetooth.gatt.GattService")) {
                 msg.arg1 = SERVICE_IBLUETOOTHGATT;
             } else {
-                Slog.e(TAG, "Unknown service connected: " + className.getClassName());
+                Slog.e(TAG, "Unknown service connected: " + name);
                 return;
             }
             msg.obj = service;
             mHandler.sendMessage(msg);
         }
 
-        public void onServiceDisconnected(ComponentName className) {
-            // Called if we unexpected disconnected.
-            if (DBG) Slog.d(TAG, "BluetoothServiceConnection, disconnected: " +
-                           className.getClassName());
+        public void onServiceDisconnected(ComponentName componentName) {
+            // Called if we unexpectedly disconnect.
+            String name = componentName.getClassName();
+            if (DBG) Slog.d(TAG, "BluetoothServiceConnection, disconnected: " + name);
             Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
-            if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
+            if (name.equals("com.android.bluetooth.btservice.AdapterService")) {
                 msg.arg1 = SERVICE_IBLUETOOTH;
-            } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
+            } else if (name.equals("com.android.bluetooth.gatt.GattService")) {
                 msg.arg1 = SERVICE_IBLUETOOTHGATT;
             } else {
-                Slog.e(TAG, "Unknown service disconnected: " + className.getClassName());
+                Slog.e(TAG, "Unknown service disconnected: " + name);
                 return;
             }
             mHandler.sendMessage(msg);
@@ -1237,7 +1242,6 @@
 
         @Override
         public void handleMessage(Message msg) {
-            if (DBG) Slog.d (TAG, "Message: " + msg.what);
             switch (msg.what) {
                 case MESSAGE_GET_NAME_AND_ADDRESS:
                     if (DBG) Slog.d(TAG, "MESSAGE_GET_NAME_AND_ADDRESS");
@@ -1275,7 +1279,7 @@
 
                 case MESSAGE_ENABLE:
                     if (DBG) {
-                        Slog.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
+                        Slog.d(TAG, "MESSAGE_ENABLE(" + msg.arg1 + "): mBluetooth = " + mBluetooth);
                     }
                     mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
                     mEnable = true;
@@ -1325,6 +1329,7 @@
                     break;
 
                 case MESSAGE_DISABLE:
+                    if (DBG) Slog.d(TAG, "MESSAGE_DISABLE: mBluetooth = " + mBluetooth);
                     mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
                     if (mEnable && mBluetooth != null) {
                         waitForOnOff(true, false);
@@ -1340,31 +1345,25 @@
                 case MESSAGE_REGISTER_ADAPTER:
                 {
                     IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
-                    boolean added = mCallbacks.register(callback);
-                    Slog.d(TAG,"Added callback: " +  (callback == null? "null": callback)  +":" +added );
-                }
+                    mCallbacks.register(callback);
                     break;
+                }
                 case MESSAGE_UNREGISTER_ADAPTER:
                 {
                     IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
-                    boolean removed = mCallbacks.unregister(callback);
-                    Slog.d(TAG,"Removed callback: " +  (callback == null? "null": callback)  +":" + removed);
+                    mCallbacks.unregister(callback);
                     break;
                 }
                 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
                 {
                     IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
-                    if (callback != null) {
-                        mStateChangeCallbacks.register(callback);
-                    }
+                    mStateChangeCallbacks.register(callback);
                     break;
                 }
                 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
                 {
                     IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
-                    if (callback != null) {
-                        mStateChangeCallbacks.unregister(callback);
-                    }
+                    mStateChangeCallbacks.unregister(callback);
                     break;
                 }
                 case MESSAGE_ADD_PROXY_DELAYED:
@@ -1438,13 +1437,11 @@
                         //Do enable request
                         try {
                             if (mQuietEnable == false) {
-                                if(!mBluetooth.enable()) {
+                                if (!mBluetooth.enable()) {
                                     Slog.e(TAG,"IBluetooth.enable() returned false");
                                 }
-                            }
-                            else
-                            {
-                                if(!mBluetooth.enableNoAutoConnect()) {
+                            } else {
+                                if (!mBluetooth.enableNoAutoConnect()) {
                                     Slog.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
                                 }
                             }
@@ -1462,19 +1459,14 @@
                     }
                     break;
                 }
-                case MESSAGE_TIMEOUT_BIND: {
-                    Slog.e(TAG, "MESSAGE_TIMEOUT_BIND");
-                    mBluetoothLock.writeLock().lock();
-                    mBinding = false;
-                    mBluetoothLock.writeLock().unlock();
-
-                    break;
-                }
                 case MESSAGE_BLUETOOTH_STATE_CHANGE:
                 {
                     int prevState = msg.arg1;
                     int newState = msg.arg2;
-                    if (DBG) Slog.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState =" + newState);
+                    if (DBG) {
+                      Slog.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: " + BluetoothAdapter.nameForState(prevState) + " > " +
+                        BluetoothAdapter.nameForState(newState));
+                    }
                     mState = newState;
                     bluetoothStateChangeHandler(prevState, newState);
                     // handle error state transition case from TURNING_ON to OFF
@@ -1514,7 +1506,7 @@
                 }
                 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
                 {
-                    Slog.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
+                    Slog.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED(" + msg.arg1 + ")");
                     try {
                         mBluetoothLock.writeLock().lock();
                         if (msg.arg1 == SERVICE_IBLUETOOTH) {
@@ -1525,7 +1517,7 @@
                             mBluetoothGatt = null;
                             break;
                         } else {
-                            Slog.e(TAG, "Bad msg.arg1: " + msg.arg1);
+                            Slog.e(TAG, "Unknown argument for service disconnect!");
                             break;
                         }
                     } finally {
@@ -1562,8 +1554,7 @@
                 }
                 case MESSAGE_RESTART_BLUETOOTH_SERVICE:
                 {
-                    Slog.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
-                        +" Restart IBluetooth service");
+                    Slog.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE");
                     /* Enable without persisting the setting as
                      it doesnt change when IBluetooth
                      service restarts */
@@ -1571,7 +1562,13 @@
                     handleEnable(mQuietEnable);
                     break;
                 }
-
+                case MESSAGE_TIMEOUT_BIND: {
+                    Slog.e(TAG, "MESSAGE_TIMEOUT_BIND");
+                    mBluetoothLock.writeLock().lock();
+                    mBinding = false;
+                    mBluetoothLock.writeLock().unlock();
+                    break;
+                }
                 case MESSAGE_TIMEOUT_UNBIND:
                 {
                     Slog.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
@@ -1657,11 +1654,10 @@
                     } else if (mBinding || mBluetooth != null) {
                         Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
                         userMsg.arg2 = 1 + msg.arg2;
-                        // if user is switched when service is being binding
-                        // delay sending MESSAGE_USER_SWITCHED
+                        // if user is switched when service is binding retry after a delay
                         mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
                         if (DBG) {
-                            Slog.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
+                            Slog.d(TAG, "Retry MESSAGE_USER_SWITCHED " + userMsg.arg2);
                         }
                     }
                     break;
@@ -1762,7 +1758,7 @@
                     parentUser == foregroundUser    ||
                     callingAppId == Process.NFC_UID ||
                     callingAppId == mSystemUiUid;
-            if (DBG) {
+            if (DBG && !valid) {
                 Slog.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
                     + " callingUser=" + callingUser
                     + " parentUser=" + parentUser
@@ -1775,7 +1771,8 @@
     }
 
     private void sendBleStateChanged(int prevState, int newState) {
-        if (DBG) Slog.d(TAG,"BLE State Change Intent: " + prevState + " -> " + newState);
+        if (DBG) Slog.d(TAG,"Sending BLE State Change: " + BluetoothAdapter.nameForState(prevState) +
+            " > " + BluetoothAdapter.nameForState(newState));
         // Send broadcast message to everyone else
         Intent intent = new Intent(BluetoothAdapter.ACTION_BLE_STATE_CHANGED);
         intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
@@ -1786,76 +1783,76 @@
 
     private void bluetoothStateChangeHandler(int prevState, int newState) {
         boolean isStandardBroadcast = true;
-        if (DBG) Slog.d(TAG, "bluetoothStateChangeHandler: " + prevState + " ->  " + newState);
-        if (prevState != newState) {
-            //Notify all proxy objects first of adapter state change
-            if (newState == BluetoothAdapter.STATE_BLE_ON ||
-                    newState == BluetoothAdapter.STATE_OFF) {
-                boolean intermediate_off = (prevState == BluetoothAdapter.STATE_TURNING_OFF
-                   && newState == BluetoothAdapter.STATE_BLE_ON);
+        if (prevState == newState) { // No change. Nothing to do.
+            return;
+        }
+        // Notify all proxy objects first of adapter state change
+        if (newState == BluetoothAdapter.STATE_BLE_ON ||
+                newState == BluetoothAdapter.STATE_OFF) {
+            boolean intermediate_off = (prevState == BluetoothAdapter.STATE_TURNING_OFF
+               && newState == BluetoothAdapter.STATE_BLE_ON);
 
-                if (newState == BluetoothAdapter.STATE_OFF) {
-                    // If Bluetooth is off, send service down event to proxy objects, and unbind
-                    if (DBG) Slog.d(TAG, "Bluetooth is complete turn off");
-                    sendBluetoothServiceDownCallback();
-                    unbindAndFinish();
-                    sendBleStateChanged(prevState, newState);
-                    // Don't broadcast as it has already been broadcast before
-                    isStandardBroadcast = false;
-
-                } else if (!intermediate_off) {
-                    // connect to GattService
-                    if (DBG) Slog.d(TAG, "Bluetooth is in LE only mode");
-                    if (mBluetoothGatt != null) {
-                        if (DBG) Slog.d(TAG, "Calling BluetoothGattServiceUp");
-                        onBluetoothGattServiceUp();
-                    } else {
-                        if (DBG) Slog.d(TAG, "Binding Bluetooth GATT service");
-                        if (mContext.getPackageManager().hasSystemFeature(
-                                                        PackageManager.FEATURE_BLUETOOTH_LE)) {
-                            Intent i = new Intent(IBluetoothGatt.class.getName());
-                            doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.CURRENT);
-                        }
-                    }
-                    sendBleStateChanged(prevState, newState);
-                    //Don't broadcase this as std intent
-                    isStandardBroadcast = false;
-
-                } else if (intermediate_off){
-                    if (DBG) Slog.d(TAG, "Intermediate off, back to LE only mode");
-                    // For LE only mode, broadcast as is
-                    sendBleStateChanged(prevState, newState);
-                    sendBluetoothStateCallback(false); // BT is OFF for general users
-                    // Broadcast as STATE_OFF
-                    newState = BluetoothAdapter.STATE_OFF;
-                    sendBrEdrDownCallback();
-                }
-            } else if (newState == BluetoothAdapter.STATE_ON) {
-                boolean isUp = (newState==BluetoothAdapter.STATE_ON);
-                sendBluetoothStateCallback(isUp);
+            if (newState == BluetoothAdapter.STATE_OFF) {
+                // If Bluetooth is off, send service down event to proxy objects, and unbind
+                if (DBG) Slog.d(TAG, "Bluetooth is complete send Service Down");
+                sendBluetoothServiceDownCallback();
+                unbindAndFinish();
                 sendBleStateChanged(prevState, newState);
-
-            } else if (newState == BluetoothAdapter.STATE_BLE_TURNING_ON ||
-                    newState == BluetoothAdapter.STATE_BLE_TURNING_OFF ) {
-                sendBleStateChanged(prevState, newState);
+                // Don't broadcast as it has already been broadcast before
                 isStandardBroadcast = false;
 
-            } else if (newState == BluetoothAdapter.STATE_TURNING_ON ||
-                    newState == BluetoothAdapter.STATE_TURNING_OFF) {
-                sendBleStateChanged(prevState, newState);
-            }
-
-            if (isStandardBroadcast) {
-                if (prevState == BluetoothAdapter.STATE_BLE_ON) {
-                    // Show prevState of BLE_ON as OFF to standard users
-                    prevState = BluetoothAdapter.STATE_OFF;
+            } else if (!intermediate_off) {
+                // connect to GattService
+                if (DBG) Slog.d(TAG, "Bluetooth is in LE only mode");
+                if (mBluetoothGatt != null) {
+                    if (DBG) Slog.d(TAG, "Calling BluetoothGattServiceUp");
+                    onBluetoothGattServiceUp();
+                } else {
+                    if (DBG) Slog.d(TAG, "Binding Bluetooth GATT service");
+                    if (mContext.getPackageManager().hasSystemFeature(
+                                                    PackageManager.FEATURE_BLUETOOTH_LE)) {
+                        Intent i = new Intent(IBluetoothGatt.class.getName());
+                        doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.CURRENT);
+                    }
                 }
-                Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
-                intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
-                intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
-                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-                mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_PERM);
+                sendBleStateChanged(prevState, newState);
+                //Don't broadcase this as std intent
+                isStandardBroadcast = false;
+
+            } else if (intermediate_off) {
+                if (DBG) Slog.d(TAG, "Intermediate off, back to LE only mode");
+                // For LE only mode, broadcast as is
+                sendBleStateChanged(prevState, newState);
+                sendBluetoothStateCallback(false); // BT is OFF for general users
+                // Broadcast as STATE_OFF
+                newState = BluetoothAdapter.STATE_OFF;
+                sendBrEdrDownCallback();
             }
+        } else if (newState == BluetoothAdapter.STATE_ON) {
+            boolean isUp = (newState == BluetoothAdapter.STATE_ON);
+            sendBluetoothStateCallback(isUp);
+            sendBleStateChanged(prevState, newState);
+
+        } else if (newState == BluetoothAdapter.STATE_BLE_TURNING_ON ||
+                newState == BluetoothAdapter.STATE_BLE_TURNING_OFF ) {
+            sendBleStateChanged(prevState, newState);
+            isStandardBroadcast = false;
+
+        } else if (newState == BluetoothAdapter.STATE_TURNING_ON ||
+                newState == BluetoothAdapter.STATE_TURNING_OFF) {
+            sendBleStateChanged(prevState, newState);
+        }
+
+        if (isStandardBroadcast) {
+            if (prevState == BluetoothAdapter.STATE_BLE_ON) {
+                // Show prevState of BLE_ON as OFF to standard users
+                prevState = BluetoothAdapter.STATE_OFF;
+            }
+            Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
+            intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
+            intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
+            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+            mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_PERM);
         }
     }
 
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index c9fd568..7572dfe 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -720,16 +720,6 @@
         mHandler = new InternalHandler(mHandlerThread.getLooper());
         mTrackerHandler = new NetworkStateTrackerHandler(mHandlerThread.getLooper());
 
-        // setup our unique device name
-        if (TextUtils.isEmpty(SystemProperties.get("net.hostname"))) {
-            String id = Settings.Secure.getString(context.getContentResolver(),
-                    Settings.Secure.ANDROID_ID);
-            if (id != null && id.length() > 0) {
-                String name = new String("android-").concat(id);
-                SystemProperties.set("net.hostname", name);
-            }
-        }
-
         mReleasePendingIntentDelayMs = Settings.Secure.getInt(context.getContentResolver(),
                 Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, 5_000);
 
@@ -866,6 +856,7 @@
 
         mAvoidBadWifiTracker = createAvoidBadWifiTracker(
                 mContext, mHandler, () -> rematchForAvoidBadWifiUpdate());
+        mAvoidBadWifiTracker.start();
     }
 
     private NetworkRequest createInternetRequestForTransport(
diff --git a/services/core/java/com/android/server/ConsumerIrService.java b/services/core/java/com/android/server/ConsumerIrService.java
index ea6812d..2ed6c77 100644
--- a/services/core/java/com/android/server/ConsumerIrService.java
+++ b/services/core/java/com/android/server/ConsumerIrService.java
@@ -29,13 +29,13 @@
 
     private static final int MAX_XMIT_TIME = 2000000; /* in microseconds */
 
-    private static native long halOpen();
-    private static native int halTransmit(long halObject, int carrierFrequency, int[] pattern);
-    private static native int[] halGetCarrierFrequencies(long halObject);
+    private static native boolean halOpen();
+    private static native int halTransmit(int carrierFrequency, int[] pattern);
+    private static native int[] halGetCarrierFrequencies();
 
     private final Context mContext;
     private final PowerManager.WakeLock mWakeLock;
-    private final long mNativeHal;
+    private final boolean mHasNativeHal;
     private final Object mHalLock = new Object();
 
     ConsumerIrService(Context context) {
@@ -45,23 +45,23 @@
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
         mWakeLock.setReferenceCounted(true);
 
-        mNativeHal = halOpen();
+        mHasNativeHal = halOpen();
         if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CONSUMER_IR)) {
-            if (mNativeHal == 0) {
+            if (!mHasNativeHal) {
                 throw new RuntimeException("FEATURE_CONSUMER_IR present, but no IR HAL loaded!");
             }
-        } else if (mNativeHal != 0) {
+        } else if (mHasNativeHal) {
             throw new RuntimeException("IR HAL present, but FEATURE_CONSUMER_IR is not set!");
         }
     }
 
     @Override
     public boolean hasIrEmitter() {
-        return mNativeHal != 0;
+        return mHasNativeHal;
     }
 
     private void throwIfNoIrEmitter() {
-        if (mNativeHal == 0) {
+        if (!mHasNativeHal) {
             throw new UnsupportedOperationException("IR emitter not available");
         }
     }
@@ -91,7 +91,7 @@
 
         // Right now there is no mechanism to ensure fair queing of IR requests
         synchronized (mHalLock) {
-            int err = halTransmit(mNativeHal, carrierFrequency, pattern);
+            int err = halTransmit(carrierFrequency, pattern);
 
             if (err < 0) {
                 Slog.e(TAG, "Error transmitting: " + err);
@@ -109,7 +109,7 @@
         throwIfNoIrEmitter();
 
         synchronized(mHalLock) {
-            return halGetCarrierFrequencies(mNativeHal);
+            return halGetCarrierFrequencies();
         }
     }
 }
diff --git a/services/core/java/com/android/server/MasterClearReceiver.java b/services/core/java/com/android/server/MasterClearReceiver.java
index 6f8edec..26e471e 100644
--- a/services/core/java/com/android/server/MasterClearReceiver.java
+++ b/services/core/java/com/android/server/MasterClearReceiver.java
@@ -42,12 +42,21 @@
                 return;
             }
         }
+        if (Intent.ACTION_MASTER_CLEAR.equals(intent.getAction())) {
+            Slog.w(TAG, "The request uses the deprecated Intent#ACTION_MASTER_CLEAR, "
+                    + "Intent#ACTION_FACTORY_RESET should be used instead.");
+        }
+        if (intent.hasExtra(Intent.EXTRA_FORCE_MASTER_CLEAR)) {
+            Slog.w(TAG, "The request uses the deprecated Intent#EXTRA_FORCE_MASTER_CLEAR, "
+                    + "Intent#EXTRA_FORCE_FACTORY_RESET should be used instead.");
+        }
 
         final boolean shutdown = intent.getBooleanExtra("shutdown", false);
         final String reason = intent.getStringExtra(Intent.EXTRA_REASON);
         final boolean wipeExternalStorage = intent.getBooleanExtra(
                 Intent.EXTRA_WIPE_EXTERNAL_STORAGE, false);
-        final boolean forceWipe = intent.getBooleanExtra(Intent.EXTRA_FORCE_MASTER_CLEAR, false);
+        final boolean forceWipe = intent.getBooleanExtra(Intent.EXTRA_FORCE_MASTER_CLEAR, false)
+                || intent.getBooleanExtra(Intent.EXTRA_FORCE_FACTORY_RESET, false);
 
         Slog.w(TAG, "!!! FACTORY RESET !!!");
         // The reboot call is blocking, so we need to do it on another thread.
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 27e4aa4..a1c3564 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -27,6 +27,7 @@
 import android.content.pm.PackageManager;
 import android.net.INetworkScoreCache;
 import android.net.INetworkScoreService;
+import android.net.NetworkKey;
 import android.net.NetworkScoreManager;
 import android.net.NetworkScorerAppManager;
 import android.net.NetworkScorerAppManager.NetworkScorerAppData;
@@ -472,6 +473,12 @@
     }
 
     @Override
+    public boolean requestScores(NetworkKey[] networks) {
+        // TODO(jjoslin): 12/13/16 - Implement
+        return false;
+    }
+
+    @Override
     protected void dump(final FileDescriptor fd, final PrintWriter writer, final String[] args) {
         mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG);
         NetworkScorerAppData currentScorer = mNetworkScorerAppManager.getActiveScorer();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2a8ad87..eae4905 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17,9 +17,11 @@
 package com.android.server.am;
 
 import android.annotation.Nullable;
+import android.app.ActivityManagerInternal.PictureInPictureArguments;
 import android.app.ApplicationThreadConstants;
 import android.app.ContentProviderHolder;
 import android.app.IActivityManager;
+import android.app.RemoteAction;
 import android.app.WaitResult;
 import android.os.IDeviceIdentifiersPolicyService;
 
@@ -202,6 +204,7 @@
 import android.os.storage.StorageManager;
 import android.provider.Downloads;
 import android.provider.Settings;
+import android.service.autofill.AutoFillService;
 import android.service.voice.IVoiceInteractionSession;
 import android.service.voice.VoiceInteractionManagerInternal;
 import android.service.voice.VoiceInteractionSession;
@@ -366,6 +369,7 @@
 import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS;
 import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
 import static com.android.server.am.ActivityStackSupervisor.RESTORE_FROM_RECENTS;
 import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
@@ -507,6 +511,9 @@
     // on getting this result before starting to launch its UI).
     static final int PENDING_ASSIST_EXTRAS_LONG_TIMEOUT = 2000;
 
+    // How long to wait in getAutoFillAssistStructure() for the activity to respond with the result.
+    static final int PENDING_AUTO_FILL_ASSIST_STRUCTURE_TIMEOUT = 2000;
+
     // Maximum number of persisted Uri grants a package is allowed
     static final int MAX_PERSISTED_URI_GRANTS = 128;
 
@@ -533,8 +540,6 @@
     private static final String INTENT_REMOTE_BUGREPORT_FINISHED =
             "android.intent.action.REMOTE_BUGREPORT_FINISHED";
 
-    // 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.
     static final boolean ANIMATE = true;
 
@@ -683,15 +688,18 @@
         public AssistStructure structure = null;
         public AssistContent content = null;
         public Bundle receiverExtras;
+        public int flags;
 
         public PendingAssistExtras(ActivityRecord _activity, Bundle _extras, Intent _intent,
-                String _hint, IResultReceiver _receiver, Bundle _receiverExtras, int _userHandle) {
+                String _hint, IResultReceiver _receiver, Bundle _receiverExtras, int _flags,
+                int _userHandle) {
             activity = _activity;
             extras = _extras;
             intent = _intent;
             hint = _hint;
             receiver = _receiver;
             receiverExtras = _receiverExtras;
+            flags = _flags;
             userHandle = _userHandle;
         }
         @Override
@@ -1213,6 +1221,15 @@
     /**
      * Set while we are wanting to sleep, to prevent any
      * activities from being started/resumed.
+     *
+     * TODO(b/33594039): Clarify the actual state transitions represented by mSleeping.
+     *
+     * Currently mSleeping is set to true when transitioning into the sleep state, and remains true
+     * while in the sleep state until there is a pending transition out of sleep, in which case
+     * mSleeping is set to false, and remains false while awake.
+     *
+     * Whether mSleeping can quickly toggled between true/false without the device actually
+     * display changing states is undefined.
      */
     private boolean mSleeping = false;
 
@@ -1362,6 +1379,7 @@
     boolean mAlwaysFinishActivities = false;
     boolean mForceResizableActivities;
     boolean mSupportsMultiWindow;
+    boolean mSupportsSplitScreenMultiWindow;
     boolean mSupportsFreeformWindowManagement;
     boolean mSupportsPictureInPicture;
     boolean mSupportsLeanbackOnly;
@@ -1544,10 +1562,10 @@
     static final int SYSTEM_USER_UNLOCK_MSG = 59;
     static final int LOG_STACK_STATE = 60;
     static final int VR_MODE_CHANGE_MSG = 61;
-    static final int VR_MODE_APPLY_IF_NEEDED_MSG = 62;
-    static final int SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG = 63;
-    static final int HANDLE_TRUST_STORAGE_UPDATE_MSG = 64;
-    static final int REPORT_LOCKED_BOOT_COMPLETE_MSG = 65;
+    static final int SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG = 62;
+    static final int HANDLE_TRUST_STORAGE_UPDATE_MSG = 63;
+    static final int REPORT_LOCKED_BOOT_COMPLETE_MSG = 64;
+    static final int NOTIFY_VR_SLEEPING_MSG = 65;
     static final int START_USER_SWITCH_FG_MSG = 712;
 
     static final int FIRST_ACTIVITY_STACK_MSG = 100;
@@ -2282,14 +2300,8 @@
                     }
                 }
                 vrService.setVrMode(vrMode, requestedPackage, userId, callingPackage);
-            } break;
-            case VR_MODE_APPLY_IF_NEEDED_MSG: {
-                final ActivityRecord r = (ActivityRecord) msg.obj;
-                final boolean needsVrMode = r != null && r.requestedVrComponent != null;
-                if (needsVrMode) {
-                    applyVrMode(msg.arg1 == 1, r.requestedVrComponent, r.userId,
-                            r.info.getComponentName(), false);
-                }
+            } case NOTIFY_VR_SLEEPING_MSG: {
+                notifyVrManagerOfSleepState(msg.arg1 != 0);
             } break;
             case HANDLE_TRUST_STORAGE_UPDATE_MSG: {
                 synchronized (ActivityManagerService.this) {
@@ -3063,20 +3075,17 @@
                 mHandler.obtainMessage(VR_MODE_CHANGE_MSG, 0, 0, r));
     }
 
-    void applyVrModeIfNeededLocked(ActivityRecord r, boolean enable) {
+    private void sendNotifyVrManagerOfSleepState(boolean isSleeping) {
         mHandler.sendMessage(
-                mHandler.obtainMessage(VR_MODE_APPLY_IF_NEEDED_MSG, enable ? 1 : 0, 0, r));
+                mHandler.obtainMessage(NOTIFY_VR_SLEEPING_MSG, isSleeping ? 1 : 0, 0));
     }
 
-    private void applyVrMode(boolean enabled, ComponentName packageName, int userId,
-            ComponentName callingPackage, boolean immediate) {
-        VrManagerInternal vrService =
-                LocalServices.getService(VrManagerInternal.class);
-        if (immediate) {
-            vrService.setVrModeImmediate(enabled, packageName, userId, callingPackage);
-        } else {
-            vrService.setVrMode(enabled, packageName, userId, callingPackage);
+    private void notifyVrManagerOfSleepState(boolean isSleeping) {
+        final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
+        if (vrService == null) {
+            return;
         }
+        vrService.onSleepStateChanged(isSleeping);
     }
 
     final void showAskCompatModeDialogLocked(ActivityRecord r) {
@@ -3674,6 +3683,15 @@
                 mNativeDebuggingApp = null;
             }
 
+            String invokeWith = null;
+            if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+                // Debuggable apps may include a wrapper script with their library directory.
+                String wrapperFileName = app.info.nativeLibraryDir + "/wrap.sh";
+                if (new File(wrapperFileName).exists()) {
+                    invokeWith = "/system/bin/logwrapper " + wrapperFileName;
+                }
+            }
+
             String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;
             if (requiredAbi == null) {
                 requiredAbi = Build.SUPPORTED_ABIS[0];
@@ -3700,12 +3718,12 @@
                 startResult = Process.startWebView(entryPoint,
                         app.processName, uid, uid, gids, debugFlags, mountExternal,
                         app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
-                        app.info.dataDir, entryPointArgs);
+                        app.info.dataDir, null, entryPointArgs);
             } else {
                 startResult = Process.start(entryPoint,
                         app.processName, uid, uid, gids, debugFlags, mountExternal,
                         app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
-                        app.info.dataDir, entryPointArgs);
+                        app.info.dataDir, invokeWith, entryPointArgs);
             }
             checkTime(startTime, "startProcess: returned from zygote!");
             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
@@ -4807,7 +4825,7 @@
                     // because we don't support returning them across task boundaries. Also, to
                     // keep backwards compatibility we remove the task from recents when finishing
                     // task with root activity.
-                    res = removeTaskByIdLocked(tr.taskId, false, finishWithRootActivity);
+                    res = mStackSupervisor.removeTaskByIdLocked(tr.taskId, false, finishWithRootActivity);
                     if (!res) {
                         Slog.i(TAG, "Removing task failed to finish activity");
                     }
@@ -5452,7 +5470,7 @@
                             tr.getBaseIntent().getComponent().getPackageName();
                     if (tr.userId != userId) continue;
                     if (!taskPackageName.equals(packageName)) continue;
-                    removeTaskByIdLocked(tr.taskId, false, REMOVE_FROM_RECENTS);
+                    mStackSupervisor.removeTaskByIdLocked(tr.taskId, false, REMOVE_FROM_RECENTS);
                 }
             }
 
@@ -7514,6 +7532,23 @@
         enterPictureInPictureMode(token, DEFAULT_DISPLAY, aspectRatio, true /* checkAspectRatio */);
     }
 
+    @Override
+    public void enterPictureInPictureModeOnMoveToBackground(IBinder token,
+            boolean enterPictureInPictureOnMoveToBg) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized(this) {
+                final ActivityRecord r = ensureValidPictureInPictureActivityLocked(
+                        "enterPictureInPictureModeOnMoveToBackground", token, -1f /* aspectRatio */,
+                        false /* checkAspectRatio */, false /* checkActivityVisibility */);
+
+                r.supportsPipOnMoveToBackground = enterPictureInPictureOnMoveToBg;
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
     private void enterPictureInPictureMode(IBinder token, int displayId, float aspectRatio,
             boolean checkAspectRatio) {
         final long origId = Binder.clearCallingIdentity();
@@ -7523,7 +7558,8 @@
                         "enterPictureInPictureMode", token, aspectRatio, checkAspectRatio,
                         true /* checkActivityVisibility */);
 
-                enterPictureInPictureModeLocked(r, displayId, aspectRatio,
+                r.pictureInPictureArgs.aspectRatio = aspectRatio;
+                enterPictureInPictureModeLocked(r, displayId, r.pictureInPictureArgs,
                         true /* moveHomeStackToFront */, "enterPictureInPictureMode");
             }
         } finally {
@@ -7531,29 +7567,13 @@
         }
     }
 
-    void enterPictureInPictureModeLocked(ActivityRecord r, int displayId, float aspectRatio,
-            boolean moveHomeStackToFront, String reason) {
-        final Rect bounds = isValidPictureInPictureAspectRatio(aspectRatio)
-                ? mWindowManager.getPictureInPictureBounds(displayId, aspectRatio)
+    void enterPictureInPictureModeLocked(ActivityRecord r, int displayId,
+            PictureInPictureArguments pipArgs, boolean moveHomeStackToFront, String reason) {
+        final Rect bounds = isValidPictureInPictureAspectRatio(pipArgs.aspectRatio)
+                ? mWindowManager.getPictureInPictureBounds(displayId, pipArgs.aspectRatio)
                 : mWindowManager.getPictureInPictureDefaultBounds(displayId);
         mStackSupervisor.moveActivityToPinnedStackLocked(r, reason, bounds, moveHomeStackToFront);
-    }
-
-    @Override
-    public void enterPictureInPictureModeOnMoveToBackground(IBinder token,
-            boolean enterPictureInPictureOnMoveToBg) {
-        final long origId = Binder.clearCallingIdentity();
-        try {
-            synchronized(this) {
-                final ActivityRecord r = ensureValidPictureInPictureActivityLocked(
-                        "requestAutoEnterPictureInPicture", token, -1f /* aspectRatio */,
-                        false /* checkAspectRatio */, false /* checkActivityVisibility */);
-
-                r.supportsPipOnMoveToBackground = enterPictureInPictureOnMoveToBg;
-            }
-        } finally {
-            Binder.restoreCallingIdentity(origId);
-        }
+        mWindowManager.setPictureInPictureActions(pipArgs.userActions);
     }
 
     @Override
@@ -7565,11 +7585,39 @@
                         "setPictureInPictureAspectRatio", token, aspectRatio,
                         true /* checkAspectRatio */, false /* checkActivityVisibility */);
 
+                r.pictureInPictureArgs.aspectRatio = aspectRatio;
                 if (r.getStack().getStackId() == PINNED_STACK_ID) {
                     // If the activity is already in picture-in-picture, update the pinned stack now
                     mWindowManager.setPictureInPictureAspectRatio(aspectRatio);
                 }
-                r.pictureInPictureAspectRatio = aspectRatio;
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public void setPictureInPictureActions(IBinder token, ParceledListSlice actionsList) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized(this) {
+                final ActivityRecord r = ensureValidPictureInPictureActivityLocked(
+                        "setPictureInPictureActions", token, -1 /* aspectRatio */,
+                        false /* checkAspectRatio */, false /* checkActivityVisibility */);
+
+                final List<RemoteAction> actions = actionsList.getList();
+                if (actions.size() > ActivityManager.getMaxNumPictureInPictureActions()) {
+                    throw new IllegalArgumentException("setPictureInPictureActions: Invalid number"
+                            + " of picture-in-picture actions.  Only a maximum of "
+                            + ActivityManager.getMaxNumPictureInPictureActions()
+                            + " actions allowed");
+                }
+
+                r.pictureInPictureArgs.userActions = actions;
+                if (r.getStack().getStackId() == PINNED_STACK_ID) {
+                    // If the activity is already in picture-in-picture, update the pinned stack now
+                    mWindowManager.setPictureInPictureActions(actions);
+                }
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -7605,7 +7653,7 @@
 
         if (!r.canEnterPictureInPicture(checkActivityVisibility)) {
             throw new IllegalArgumentException(caller
-                    + "Current activity does not support picture-in-picture or is not "
+                    + ": Current activity does not support picture-in-picture or is not "
                     + "visible r=" + r);
         }
 
@@ -9536,79 +9584,6 @@
         mWindowManager.executeAppTransition();
     }
 
-    private void cleanUpRemovedTaskLocked(TaskRecord tr, boolean killProcess,
-            boolean removeFromRecents) {
-        if (removeFromRecents) {
-            mRecentTasks.remove(tr);
-            tr.removedFromRecents();
-        }
-        ComponentName component = tr.getBaseIntent().getComponent();
-        if (component == null) {
-            Slog.w(TAG, "No component for base intent of task: " + tr);
-            return;
-        }
-
-        // Find any running services associated with this app and stop if needed.
-        mServices.cleanUpRemovedTaskLocked(tr, component, new Intent(tr.getBaseIntent()));
-
-        if (!killProcess) {
-            return;
-        }
-
-        // Determine if the process(es) for this task should be killed.
-        final String pkg = component.getPackageName();
-        ArrayList<ProcessRecord> procsToKill = new ArrayList<>();
-        ArrayMap<String, SparseArray<ProcessRecord>> pmap = mProcessNames.getMap();
-        for (int i = 0; i < pmap.size(); i++) {
-
-            SparseArray<ProcessRecord> uids = pmap.valueAt(i);
-            for (int j = 0; j < uids.size(); j++) {
-                ProcessRecord proc = uids.valueAt(j);
-                if (proc.userId != tr.userId) {
-                    // Don't kill process for a different user.
-                    continue;
-                }
-                if (proc == mHomeProcess) {
-                    // Don't kill the home process along with tasks from the same package.
-                    continue;
-                }
-                if (!proc.pkgList.containsKey(pkg)) {
-                    // Don't kill process that is not associated with this task.
-                    continue;
-                }
-
-                for (int k = 0; k < proc.activities.size(); k++) {
-                    TaskRecord otherTask = proc.activities.get(k).task;
-                    if (tr.taskId != otherTask.taskId && otherTask.inRecents) {
-                        // Don't kill process(es) that has an activity in a different task that is
-                        // also in recents.
-                        return;
-                    }
-                }
-
-                if (proc.foregroundServices) {
-                    // Don't kill process(es) with foreground service.
-                    return;
-                }
-
-                // Add process to kill list.
-                procsToKill.add(proc);
-            }
-        }
-
-        // Kill the running processes.
-        for (int i = 0; i < procsToKill.size(); i++) {
-            ProcessRecord pr = procsToKill.get(i);
-            if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND
-                    && pr.curReceivers.isEmpty()) {
-                pr.kill("remove task", true);
-            } else {
-                // We delay killing processes that are not in the background or running a receiver.
-                pr.waitingToKill = "remove task";
-            }
-        }
-    }
-
     private void removeTasksByPackageNameLocked(String packageName, int userId) {
         // Remove all tasks with activities in the specified package from the list of recent tasks
         for (int i = mRecentTasks.size() - 1; i >= 0; i--) {
@@ -9618,7 +9593,7 @@
             ComponentName cn = tr.intent.getComponent();
             if (cn != null && cn.getPackageName().equals(packageName)) {
                 // If the package name matches, remove the task.
-                removeTaskByIdLocked(tr.taskId, true, REMOVE_FROM_RECENTS);
+                mStackSupervisor.removeTaskByIdLocked(tr.taskId, true, REMOVE_FROM_RECENTS);
             }
         }
     }
@@ -9636,35 +9611,11 @@
             final boolean sameComponent = cn != null && cn.getPackageName().equals(packageName)
                     && (filterByClasses == null || filterByClasses.contains(cn.getClassName()));
             if (sameComponent) {
-                removeTaskByIdLocked(tr.taskId, false, REMOVE_FROM_RECENTS);
+                mStackSupervisor.removeTaskByIdLocked(tr.taskId, false, REMOVE_FROM_RECENTS);
             }
         }
     }
 
-    /**
-     * Removes the task with the specified task id.
-     *
-     * @param taskId Identifier of the task to be removed.
-     * @param killProcess Kill any process associated with the task if possible.
-     * @param removeFromRecents Whether to also remove the task from recents.
-     * @return Returns true if the given task was found and removed.
-     */
-    private boolean removeTaskByIdLocked(int taskId, boolean killProcess,
-            boolean removeFromRecents) {
-        final TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(
-                taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID);
-        if (tr != null) {
-            tr.removeTaskActivitiesLocked();
-            cleanUpRemovedTaskLocked(tr, killProcess, removeFromRecents);
-            if (tr.isPersistable) {
-                notifyTaskPersisterLocked(null, true);
-            }
-            return true;
-        }
-        Slog.w(TAG, "Request to remove task ignored for non-existent task " + taskId);
-        return false;
-    }
-
     @Override
     public void removeStack(int stackId) {
         enforceCallingPermission(Manifest.permission.MANAGE_ACTIVITY_STACKS, "removeStack()");
@@ -9675,15 +9626,7 @@
         synchronized (this) {
             final long ident = Binder.clearCallingIdentity();
             try {
-                final ActivityStack stack = mStackSupervisor.getStack(stackId);
-                if (stack == null) {
-                    return;
-                }
-                final ArrayList<TaskRecord> tasks = stack.getAllTasks();
-                for (int i = tasks.size() - 1; i >= 0; i--) {
-                    removeTaskByIdLocked(
-                            tasks.get(i).taskId, true /* killProcess */, REMOVE_FROM_RECENTS);
-                }
+                mStackSupervisor.removeStackLocked(stackId);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -9712,7 +9655,7 @@
         synchronized (this) {
             final long ident = Binder.clearCallingIdentity();
             try {
-                return removeTaskByIdLocked(taskId, true, REMOVE_FROM_RECENTS);
+                return mStackSupervisor.removeTaskByIdLocked(taskId, true, REMOVE_FROM_RECENTS);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -11685,6 +11628,7 @@
             startTimeTrackingFocusedActivityLocked();
             mTopProcessState = ActivityManager.PROCESS_STATE_TOP;
             mStackSupervisor.comeOutOfSleepIfNeededLocked();
+            sendNotifyVrManagerOfSleepState(false);
             updateOomAdjLocked();
         } else if (!mSleeping && shouldSleepLocked()) {
             mSleeping = true;
@@ -11693,6 +11637,7 @@
             }
             mTopProcessState = ActivityManager.PROCESS_STATE_TOP_SLEEPING;
             mStackSupervisor.goingToSleepLocked();
+            sendNotifyVrManagerOfSleepState(true);
             updateOomAdjLocked();
 
             // Initialize the wake times of all processes.
@@ -12178,7 +12123,7 @@
     public Bundle getAssistContextExtras(int requestType) {
         PendingAssistExtras pae = enqueueAssistContext(requestType, null, null, null,
                 null, null, true /* focused */, true /* newSessionId */,
-                UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT);
+                UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT, 0);
         if (pae == null) {
             return null;
         }
@@ -12246,22 +12191,23 @@
             IBinder activityToken, boolean focused, boolean newSessionId) {
         return enqueueAssistContext(requestType, null, null, receiver, receiverExtras,
                 activityToken, focused, newSessionId,
-                UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_LONG_TIMEOUT)
+                UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_LONG_TIMEOUT, 0)
                 != null;
     }
 
     @Override
     public boolean requestAutoFillData(IResultReceiver receiver, Bundle receiverExtras,
-            IBinder activityToken) {
-        return enqueueAssistContext(ActivityManager.ASSIST_CONTEXT_AUTOFILL, null, null, receiver,
+            IBinder activityToken, int flags) {
+        return enqueueAssistContext(ActivityManager.ASSIST_CONTEXT_FULL, null, null, receiver,
                 receiverExtras, activityToken, true, true,
-                UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_LONG_TIMEOUT)
-                != null;
+                UserHandle.getCallingUserId(), null, PENDING_AUTO_FILL_ASSIST_STRUCTURE_TIMEOUT,
+                flags) != null;
     }
 
     private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint,
             IResultReceiver receiver, Bundle receiverExtras, IBinder activityToken,
-            boolean focused, boolean newSessionId, int userHandle, Bundle args, long timeout) {
+            boolean focused, boolean newSessionId, int userHandle, Bundle args, long timeout,
+            int flags) {
         enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO,
                 "enqueueAssistContext()");
         synchronized (this) {
@@ -12300,14 +12246,14 @@
             extras.putString(Intent.EXTRA_ASSIST_PACKAGE, activity.packageName);
             extras.putInt(Intent.EXTRA_ASSIST_UID, activity.app.uid);
             pae = new PendingAssistExtras(activity, extras, intent, hint, receiver, receiverExtras,
-                    userHandle);
+                    flags, userHandle);
             // Increment the sessionId if necessary
             if (newSessionId) {
                 mViSessionId++;
             }
             try {
                 activity.app.thread.requestAssistContextExtras(activity.appToken, pae,
-                        requestType, mViSessionId);
+                        requestType, mViSessionId, flags);
                 mPendingAssistExtras.add(pae);
                 mUiHandler.postDelayed(pae, timeout);
             } catch (RemoteException e) {
@@ -12383,10 +12329,13 @@
                 sendBundle.putParcelable(VoiceInteractionSession.KEY_CONTENT, pae.content);
                 sendBundle.putBundle(VoiceInteractionSession.KEY_RECEIVER_EXTRAS,
                         pae.receiverExtras);
+                if (pae.flags > 0) {
+                    sendBundle.putInt(VoiceInteractionSession.KEY_FLAGS, pae.flags);
+                }
                 IBinder autoFillCallback =
-                        extras.getBinder(VoiceInteractionSession.KEY_AUTO_FILL_CALLBACK);
+                        extras.getBinder(AutoFillService.KEY_CALLBACK);
                 if (autoFillCallback != null) {
-                    sendBundle.putBinder(VoiceInteractionSession.KEY_AUTO_FILL_CALLBACK,
+                    sendBundle.putBinder(AutoFillService.KEY_CALLBACK,
                             autoFillCallback);
                 }
             }
@@ -12420,7 +12369,7 @@
             Bundle args) {
         return enqueueAssistContext(requestType, intent, hint, null, null, null,
                 true /* focused */, true /* newSessionId */,
-                userHandle, args, PENDING_ASSIST_EXTRAS_TIMEOUT) != null;
+                userHandle, args, PENDING_ASSIST_EXTRAS_TIMEOUT, 0) != null;
     }
 
     public void registerProcessObserver(IProcessObserver observer) {
@@ -13136,6 +13085,8 @@
                 mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
 
         final boolean supportsMultiWindow = ActivityManager.supportsMultiWindow();
+        final boolean supportsSplitScreenMultiWindow =
+                ActivityManager.supportsSplitScreenMultiWindow();
         final String debugApp = Settings.Global.getString(resolver, DEBUG_APP);
         final boolean waitForDebugger = Settings.Global.getInt(resolver, WAIT_FOR_DEBUGGER, 0) != 0;
         final boolean alwaysFinishActivities =
@@ -13171,6 +13122,7 @@
                 mSupportsFreeformWindowManagement = false;
                 mSupportsPictureInPicture = false;
             }
+            mSupportsSplitScreenMultiWindow = supportsSplitScreenMultiWindow;
             mWindowManager.setForceResizableTasks(mForceResizableActivities);
             mWindowManager.setSupportsPictureInPicture(mSupportsPictureInPicture);
             // This happens before any activities are started, so we can change global configuration
@@ -17860,6 +17812,7 @@
                 || Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)
                 || Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(action)
                 || Intent.ACTION_MASTER_CLEAR.equals(action)
+                || Intent.ACTION_FACTORY_RESET.equals(action)
                 || AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
                 || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)
                 || LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)
@@ -22222,22 +22175,6 @@
         public SleepToken acquireSleepToken(String tag) {
             Preconditions.checkNotNull(tag);
 
-            ComponentName requestedVrService = null;
-            ComponentName callingVrActivity = null;
-            int userId = -1;
-            synchronized (ActivityManagerService.this) {
-                final ActivityRecord resumedActivity = mStackSupervisor.getResumedActivityLocked();
-                if (resumedActivity != null) {
-                    requestedVrService = resumedActivity.requestedVrComponent;
-                    callingVrActivity = resumedActivity.info.getComponentName();
-                    userId = resumedActivity.userId;
-                }
-            }
-
-            if (requestedVrService != null) {
-                applyVrMode(false, requestedVrService, userId, callingVrActivity, true);
-            }
-
             synchronized (ActivityManagerService.this) {
                 SleepTokenImpl token = new SleepTokenImpl(tag);
                 mSleepTokens.add(token);
@@ -22477,7 +22414,8 @@
                 long origId = Binder.clearCallingIdentity();
                 try {
                     // We remove the task from recents to preserve backwards
-                    if (!removeTaskByIdLocked(mTaskId, false, REMOVE_FROM_RECENTS)) {
+                    if (!mStackSupervisor.removeTaskByIdLocked(mTaskId, false,
+                            REMOVE_FROM_RECENTS)) {
                         throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
                     }
                 } finally {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 14b843a..814b05a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -233,6 +233,8 @@
                     return runAttachAgent(pw);
                 case "supports-multiwindow":
                     return runSupportsMultiwindow(pw);
+                case "supports-split-screen-multi-window":
+                    return runSupportsSplitScreenMultiwindow(pw);
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -2300,20 +2302,36 @@
     }
 
     int runSupportsMultiwindow(PrintWriter pw) throws RemoteException {
+        final Resources res = getResources(pw);
+        if (res == null) {
+            return -1;
+        }
+        pw.println(res.getBoolean(com.android.internal.R.bool.config_supportsMultiWindow));
+        return 0;
+    }
+
+    int runSupportsSplitScreenMultiwindow(PrintWriter pw) throws RemoteException {
+        final Resources res = getResources(pw);
+        if (res == null) {
+            return -1;
+        }
+        pw.println(
+                res.getBoolean(com.android.internal.R.bool.config_supportsSplitScreenMultiWindow));
+        return 0;
+    }
+
+    private Resources getResources(PrintWriter pw) throws RemoteException {
         // system resources does not contain all the device configuration, construct it manually.
         Configuration config = mInterface.getConfiguration();
         if (config == null) {
             pw.println("Error: Activity manager has no configuration");
-            return -1;
+            return null;
         }
 
         final DisplayMetrics metrics = new DisplayMetrics();
         metrics.setToDefaults();
 
-        Resources res = new Resources(AssetManager.getSystem(), metrics, config);
-
-        pw.println(res.getBoolean(com.android.internal.R.bool.config_supportsMultiWindow));
-        return 0;
+        return new Resources(AssetManager.getSystem(), metrics, config);
     }
 
     @Override
@@ -2495,6 +2513,8 @@
             pw.println("      Rtrieve the configuration and any recent configurations of the device.");
             pw.println("  supports-multiwindow");
             pw.println("      Returns true if the device supports multiwindow.");
+            pw.println("  supports-split-screen-multi-window");
+            pw.println("      Returns true if the device supports split screen multiwindow.");
             pw.println("  suppress-resize-config-changes <true|false>");
             pw.println("      Suppresses configuration changes due to user resizing an activity/task.");
             pw.println("  set-inactive [--user <USER_ID>] <PACKAGE> true|false");
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 13c422b..ef19700 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -54,6 +54,7 @@
 
 import android.annotation.NonNull;
 import android.app.ActivityManager.TaskDescription;
+import android.app.ActivityManagerInternal.PictureInPictureArguments;
 import android.app.ActivityOptions;
 import android.app.PendingIntent;
 import android.app.ResultInfo;
@@ -217,13 +218,13 @@
     boolean immersive;      // immersive mode (don't interrupt if possible)
     boolean forceNewConfig; // force re-create with new config next time
     boolean supportsPipOnMoveToBackground;   // Supports automatically entering picture-in-picture
-            // when this activity is hidden. This flag is requested by the activity.
+        // when this activity is hidden. This flag is requested by the activity.
     private boolean enterPipOnMoveToBackground; // Flag to enter picture in picture when this
-            // activity is made invisible. This flag is set specifically when another task is being
-            // launched or moved to the front which may cause this activity to try and enter PiP
-            // when it is next made invisible.
-    float pictureInPictureAspectRatio; // The aspect ratio to use when auto-entering
-            // picture-in-picture
+        // activity is made invisible. This flag is set specifically when another task is being
+        // launched or moved to the front which may cause this activity to try and enter PiP
+        // when it is next made invisible.
+    PictureInPictureArguments pictureInPictureArgs = new PictureInPictureArguments();  // The PiP
+        // arguments used when deferring the entering of picture-in-picture.
     int launchCount;        // count of launches since last state
     long lastLaunchTime;    // time of last launch of this activity
     ComponentName requestedVrComponent; // the requested component for handling VR mode.
@@ -441,9 +442,10 @@
             pw.println(prefix + "resizeMode=" + ActivityInfo.resizeModeToString(info.resizeMode));
         }
         if (supportsPipOnMoveToBackground) {
-            pw.println(prefix + "supportsPipOnMoveToBackground=1 "
-                    + "enterPipOnMoveToBackground="
-                            + (enterPipOnMoveToBackground ? 1 : 0));
+            pw.println(prefix + "supportsPipOnMoveToBackground=1");
+            pw.println(prefix + "enterPipOnMoveToBackground=" +
+                    (enterPipOnMoveToBackground ? 1 : 0));
+            pictureInPictureArgs.dump(pw, prefix);
         }
     }
 
@@ -967,7 +969,7 @@
             return supportsPictureInPicture();
         }
 
-        if (supportsPictureInPicture() && visible) {
+        if (supportsPictureInPicture()) {
             switch (state) {
                 case RESUMED:
                 case PAUSING:
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index d160a46..5bdae57 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1895,7 +1895,7 @@
             // since it will affect the focused stack's visibility and occlude
             // starting activities
             mService.enterPictureInPictureModeLocked(r, r.getDisplayId(),
-                    r.pictureInPictureAspectRatio, false /* moveHomeStackToFront */,
+                    r.pictureInPictureArgs, false /* moveHomeStackToFront */,
                     "ensureActivitiesVisibleLocked");
             return true;
         }
@@ -2150,9 +2150,7 @@
                     mStackSupervisor.allResumedActivitiesComplete()) {
             // Make sure we have executed any pending transitions, since there
             // should be nothing left to do at this point.
-            mWindowManager.executeAppTransition();
-            mNoAnimActivities.clear();
-            ActivityOptions.abort(options);
+            executeAppTransition(options);
             if (DEBUG_STATES) Slog.d(TAG_STATES,
                     "resumeTopActivityLocked: Top activity resumed " + next);
             if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
@@ -2187,9 +2185,7 @@
                 && mStackSupervisor.allPausedActivitiesComplete()) {
             // Make sure we have executed any pending transitions, since there
             // should be nothing left to do at this point.
-            mWindowManager.executeAppTransition();
-            mNoAnimActivities.clear();
-            ActivityOptions.abort(options);
+            executeAppTransition(options);
             if (DEBUG_STATES) Slog.d(TAG_STATES,
                     "resumeTopActivityLocked: Going to sleep and all paused");
             if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
@@ -2252,9 +2248,7 @@
             // So, nothing else to-do except:
             // Make sure we have executed any pending transitions, since there
             // should be nothing left to do at this point.
-            mWindowManager.executeAppTransition();
-            mNoAnimActivities.clear();
-            ActivityOptions.abort(options);
+            executeAppTransition(options);
             if (DEBUG_STATES) Slog.d(TAG_STATES,
                     "resumeTopActivityLocked: Top activity resumed (dontWaitForPause) " + next);
             if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
@@ -2857,7 +2851,7 @@
                 } else {
                     targetTask = createTaskRecord(
                             mStackSupervisor.getNextTaskIdForUserLocked(target.userId),
-                            target.info, null, null, null, false);
+                            target.info, null, null, null, false, target.mActivityType);
                     targetTask.affinityIntent = target.intent;
                     if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " + target
                             + " out to new task " + target.task);
@@ -4897,9 +4891,9 @@
 
     TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
-            boolean toTop) {
+            boolean toTop, int type) {
         TaskRecord task = new TaskRecord(mService, taskId, info, intent, voiceSession,
-                voiceInteractor);
+                voiceInteractor, type);
         // add the task to stack first, mTaskPositioner might need the stack association
         addTask(task, toTop, "createTaskRecord");
         final boolean isLockscreenShown =
@@ -4908,6 +4902,11 @@
                 && !isLockscreenShown) {
             task.updateOverrideConfiguration(mBounds);
         }
+        final Rect bounds = task.updateOverrideConfigurationFromLaunchBounds();
+        final boolean showForAllUsers = (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0;
+        mWindowManager.addTask(taskId, mStackId, task.userId, bounds,
+                task.getOverrideConfiguration(), task.mResizeMode, task.isHomeTask(),
+                task.isOnTopLauncher(), toTop, showForAllUsers);
         return task;
     }
 
@@ -4974,15 +4973,13 @@
     }
 
     void addConfigOverride(ActivityRecord r, TaskRecord task) {
-        final Rect bounds = task.updateOverrideConfigurationFromLaunchBounds();
+        task.updateOverrideConfigurationFromLaunchBounds();
         // TODO: VI deal with activity
         mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
-                r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
-                (r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId, r.info.configChanges,
-                task.voiceSession != null, r.mLaunchTaskBehind, bounds,
-                task.getOverrideConfiguration(), task.mResizeMode, r.isAlwaysFocusable(),
-                task.isHomeTask(), r.appInfo.targetSdkVersion, r.mRotationAnimationHint,
-                task.isOnTopLauncher());
+                r.task.taskId, r.info.screenOrientation, r.fullscreen,
+                (r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.info.configChanges,
+                task.voiceSession != null, r.mLaunchTaskBehind, r.isAlwaysFocusable(),
+                r.appInfo.targetSdkVersion, r.mRotationAnimationHint);
         r.onOverrideConfigurationSent();
     }
 
@@ -5021,7 +5018,7 @@
 
         final TaskRecord task = createTaskRecord(
                 mStackSupervisor.getNextTaskIdForUserLocked(r.userId),
-                r.info, r.intent, null, null, true);
+                r.info, r.intent, null, null, true, r.mActivityType);
         r.setTask(task, null);
         task.addActivityToTop(r);
         setAppTask(r, task);
@@ -5033,10 +5030,8 @@
     }
 
     private void setAppTask(ActivityRecord r, TaskRecord task) {
-        final Rect bounds = task.updateOverrideConfigurationFromLaunchBounds();
-        mWindowManager.setAppTask(r.appToken, task.taskId, mStackId, bounds,
-                task.getOverrideConfiguration(), task.mResizeMode, task.isHomeTask(),
-                task.isOnTopLauncher());
+        task.updateOverrideConfigurationFromLaunchBounds();
+        mWindowManager.addAppToTask(r.appToken, task.taskId);
         r.onOverrideConfigurationSent();
     }
 
@@ -5055,4 +5050,10 @@
             mTaskHistory.get(taskNdx).setLockTaskAuth();
         }
     }
+
+    void executeAppTransition(ActivityOptions options) {
+        mWindowManager.executeAppTransition();
+        mNoAnimActivities.clear();
+        ActivityOptions.abort(options);
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 281812c..b4b3465 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -249,6 +249,9 @@
     // Don't execute any calls to resume.
     static final boolean DEFER_RESUME = true;
 
+    // Used to indicate that a task is removed it should also be removed from recents.
+    static final boolean REMOVE_FROM_RECENTS = true;
+
     // Activity actions an app cannot start if it uses a permission which is not granted.
     private static final ArrayMap<String, String> ACTION_TO_RUNTIME_PERMISSION =
             new ArrayMap<>();
@@ -1844,6 +1847,9 @@
         final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
         if (r == null || r.state != RESUMED) {
             mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
+        } else if (r.state == RESUMED) {
+            // Kick off any lingering app transitions form the MoveTaskToFront operation.
+            mFocusedStack.executeAppTransition(targetOptions);
         }
         return false;
     }
@@ -2180,7 +2186,8 @@
                         // Update the return-to to reflect where the pinned stack task was moved
                         // from so that we retain the stack that was previously visible if the
                         // pinned stack is recreated. See moveActivityToPinnedStackLocked().
-                        task.setTaskToReturnTo(getFocusedStack().getStackId() == HOME_STACK_ID
+                        final int focusedStackId = getFocusedStack().getStackId();
+                        task.setTaskToReturnTo(focusedStackId == HOME_STACK_ID || !onTop
                                 ? HOME_ACTIVITY_TYPE : APPLICATION_ACTIVITY_TYPE);
                     }
                     moveTaskToStackLocked(tasks.get(i).taskId,
@@ -2371,6 +2378,141 @@
         return activityContainer.mStack;
     }
 
+    /**
+     * Removes the stack associed with the given {@param stackId}.  If the {@param stackId} is the
+     * pinned stack, then its tasks are not explicitly removed when the stack is destroyed, but
+     * instead moved back onto the fullscreen stack.
+     */
+    void removeStackLocked(int stackId) {
+        final ActivityStack stack = getStack(stackId);
+        if (stack == null) {
+            return;
+        }
+
+        final ArrayList<TaskRecord> tasks = stack.getAllTasks();
+        if (stack.getStackId() == PINNED_STACK_ID) {
+            final ActivityStack fullscreenStack = getStack(FULLSCREEN_WORKSPACE_STACK_ID);
+            if (fullscreenStack != null) {
+                final boolean isFullscreenStackVisible =
+                        fullscreenStack.getStackVisibilityLocked(null) == STACK_VISIBLE;
+                for (int i = 0; i < tasks.size(); i++) {
+                    // Insert the task either at the top of the fullscreen stack if it is hidden,
+                    // or just under the top task if it is currently visible
+                    final int insertPosition = isFullscreenStackVisible
+                            ? Math.max(0, fullscreenStack.getChildCount() - 1)
+                            : fullscreenStack.getChildCount();
+                    positionTaskInStackLocked(tasks.get(i).taskId, FULLSCREEN_WORKSPACE_STACK_ID,
+                            insertPosition);
+                }
+                ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+                resumeFocusedStackTopActivityLocked();
+            } else {
+                // If there is no fullscreen stack, then create the stack and move all the tasks
+                // onto the stack
+                moveTasksToFullscreenStackLocked(PINNED_STACK_ID, false /* onTop */);
+            }
+        } else {
+            for (int i = tasks.size() - 1; i >= 0; i--) {
+                removeTaskByIdLocked(tasks.get(i).taskId, true /* killProcess */,
+                        REMOVE_FROM_RECENTS);
+            }
+        }
+    }
+
+    /**
+     * Removes the task with the specified task id.
+     *
+     * @param taskId Identifier of the task to be removed.
+     * @param killProcess Kill any process associated with the task if possible.
+     * @param removeFromRecents Whether to also remove the task from recents.
+     * @return Returns true if the given task was found and removed.
+     */
+    boolean removeTaskByIdLocked(int taskId, boolean killProcess, boolean removeFromRecents) {
+        final TaskRecord tr = anyTaskForIdLocked(taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID);
+        if (tr != null) {
+            tr.removeTaskActivitiesLocked();
+            cleanUpRemovedTaskLocked(tr, killProcess, removeFromRecents);
+            if (tr.isPersistable) {
+                mService.notifyTaskPersisterLocked(null, true);
+            }
+            return true;
+        }
+        Slog.w(TAG, "Request to remove task ignored for non-existent task " + taskId);
+        return false;
+    }
+
+    void cleanUpRemovedTaskLocked(TaskRecord tr, boolean killProcess, boolean removeFromRecents) {
+        if (removeFromRecents) {
+            mRecentTasks.remove(tr);
+            tr.removedFromRecents();
+        }
+        ComponentName component = tr.getBaseIntent().getComponent();
+        if (component == null) {
+            Slog.w(TAG, "No component for base intent of task: " + tr);
+            return;
+        }
+
+        // Find any running services associated with this app and stop if needed.
+        mService.mServices.cleanUpRemovedTaskLocked(tr, component, new Intent(tr.getBaseIntent()));
+
+        if (!killProcess) {
+            return;
+        }
+
+        // Determine if the process(es) for this task should be killed.
+        final String pkg = component.getPackageName();
+        ArrayList<ProcessRecord> procsToKill = new ArrayList<>();
+        ArrayMap<String, SparseArray<ProcessRecord>> pmap = mService.mProcessNames.getMap();
+        for (int i = 0; i < pmap.size(); i++) {
+
+            SparseArray<ProcessRecord> uids = pmap.valueAt(i);
+            for (int j = 0; j < uids.size(); j++) {
+                ProcessRecord proc = uids.valueAt(j);
+                if (proc.userId != tr.userId) {
+                    // Don't kill process for a different user.
+                    continue;
+                }
+                if (proc == mService.mHomeProcess) {
+                    // Don't kill the home process along with tasks from the same package.
+                    continue;
+                }
+                if (!proc.pkgList.containsKey(pkg)) {
+                    // Don't kill process that is not associated with this task.
+                    continue;
+                }
+
+                for (int k = 0; k < proc.activities.size(); k++) {
+                    TaskRecord otherTask = proc.activities.get(k).task;
+                    if (tr.taskId != otherTask.taskId && otherTask.inRecents) {
+                        // Don't kill process(es) that has an activity in a different task that is
+                        // also in recents.
+                        return;
+                    }
+                }
+
+                if (proc.foregroundServices) {
+                    // Don't kill process(es) with foreground service.
+                    return;
+                }
+
+                // Add process to kill list.
+                procsToKill.add(proc);
+            }
+        }
+
+        // Kill the running processes.
+        for (int i = 0; i < procsToKill.size(); i++) {
+            ProcessRecord pr = procsToKill.get(i);
+            if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND
+                    && pr.curReceivers.isEmpty()) {
+                pr.kill("remove task", true);
+            } else {
+                // We delay killing processes that are not in the background or running a receiver.
+                pr.waitingToKill = "remove task";
+            }
+        }
+    }
+
     int getNextStackId() {
         while (true) {
             if (mNextFreeStackId >= FIRST_DYNAMIC_STACK_ID
@@ -2424,7 +2566,11 @@
             return false;
         }
 
-        stack.addTask(task, false, "restoreRecentTask");
+        stack.addTask(task, false /* toTop */, "restoreRecentTask");
+        final Rect bounds = task.updateOverrideConfigurationFromLaunchBounds();
+        mWindowManager.addTask(task.taskId, stack.mStackId, task.userId, bounds,
+                task.getOverrideConfiguration(), task.mResizeMode, task.isHomeTask(),
+                task.isOnTopLauncher(), false /* toTop */, true /* showForAllUsers */);
         if (DEBUG_RECENTS) Slog.v(TAG_RECENTS,
                 "Added restored task=" + task + " to stack=" + stack);
         final ArrayList<ActivityRecord> activities = task.mActivities;
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index d0960a0..3bb9ccc 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1642,8 +1642,8 @@
             final TaskRecord task = mTargetStack.createTaskRecord(
                     mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId),
                     mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
-                    mNewTaskIntent != null ? mNewTaskIntent : mIntent,
-                    mVoiceSession, mVoiceInteractor, !mLaunchTaskBehind /* toTop */);
+                    mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
+                    mVoiceInteractor, !mLaunchTaskBehind /* toTop */, mStartActivity.mActivityType);
             mStartActivity.setTask(task, taskToAffiliate);
             if (mLaunchBounds != null) {
                 final int stackId = mTargetStack.mStackId;
@@ -1817,8 +1817,8 @@
         }
         final ActivityRecord prev = mTargetStack.topActivity();
         final TaskRecord task = (prev != null) ? prev.task : mTargetStack.createTaskRecord(
-                        mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId),
-                        mStartActivity.info, mIntent, null, null, true);
+                mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId), mStartActivity.info,
+                mIntent, null, null, true, mStartActivity.mActivityType);
         mStartActivity.setTask(task, null);
         mWindowManager.moveTaskToTop(mStartActivity.task.taskId);
         if (DEBUG_TASKS) Slog.v(TAG_TASKS,
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index 19bf536..cfe2eb0 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -121,8 +121,6 @@
                 // Some stack visibility might change (e.g. docked stack)
                 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
                 mWindowManager.executeAppTransition();
-                mService.applyVrModeIfNeededLocked(mStackSupervisor.getResumedActivityLocked(),
-                        true /* enable */);
             } finally {
                 mWindowManager.continueSurfaceLayout();
             }
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 383f106..9e28068 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -281,7 +281,7 @@
     private Configuration mTmpConfig = new Configuration();
 
     TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
-            IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
+            IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, int type) {
         mService = service;
         mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
                 TaskPersister.IMAGE_EXTENSION;
@@ -296,6 +296,7 @@
         mActivities = new ArrayList<>();
         mCallingUid = info.applicationInfo.uid;
         mCallingPackage = info.packageName;
+        taskType = type;
         setIntent(_intent, info);
         setMinDimensions(info);
         touchActiveTime();
@@ -321,7 +322,6 @@
         setIntent(_intent, info);
         setMinDimensions(info);
 
-        taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE;
         isPersistable = true;
         // Clamp to [1, max].
         maxRecents = Math.min(Math.max(info.maxRecents, 1),
@@ -1104,7 +1104,7 @@
     }
 
     boolean canGoInDockedStack() {
-        return isResizeable() &&
+        return isResizeable() && mService.mSupportsSplitScreenMultiWindow &&
                 !ActivityInfo.isPreserveOrientationMode(mResizeMode);
     }
 
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
index 372b2d8..d5fa26c 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
@@ -43,10 +43,10 @@
     private IpConnectivityEventBuilder() {
     }
 
-    public static byte[] serialize(int dropped, List<ConnectivityMetricsEvent> events)
+    public static byte[] serialize(int dropped, List<IpConnectivityEvent> events)
             throws IOException {
         final IpConnectivityLog log = new IpConnectivityLog();
-        log.events = toProto(events);
+        log.events = events.toArray(new IpConnectivityEvent[events.size()]);
         log.droppedEvents = dropped;
         if ((log.events.length > 0) || (dropped > 0)) {
             // Only write version number if log has some information at all.
@@ -55,7 +55,7 @@
         return IpConnectivityLog.toByteArray(log);
     }
 
-    public static IpConnectivityEvent[] toProto(List<ConnectivityMetricsEvent> eventsIn) {
+    public static List<IpConnectivityEvent> toProto(List<ConnectivityMetricsEvent> eventsIn) {
         final ArrayList<IpConnectivityEvent> eventsOut = new ArrayList<>(eventsIn.size());
         for (ConnectivityMetricsEvent in : eventsIn) {
             final IpConnectivityEvent out = toProto(in);
@@ -64,7 +64,7 @@
             }
             eventsOut.add(out);
         }
-        return eventsOut.toArray(new IpConnectivityEvent[eventsOut.size()]);
+        return eventsOut;
     }
 
     public static IpConnectivityEvent toProto(ConnectivityMetricsEvent ev) {
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
index 42f439c..445f606 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
@@ -36,14 +36,14 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.TokenBucket;
 import com.android.server.SystemService;
+import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.List;
 import java.util.function.ToIntFunction;
 
-import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
-
 /** {@hide} */
 final public class IpConnectivityMetrics extends SystemService {
     private static final String TAG = IpConnectivityMetrics.class.getSimpleName();
@@ -63,6 +63,8 @@
     // Maximum size of the event buffer.
     private static final int MAXIMUM_BUFFER_SIZE = DEFAULT_BUFFER_SIZE * 10;
 
+    private static final int MAXIMUM_CONNECT_LATENCY_RECORDS = 20000;
+
     private static final int ERROR_RATE_LIMITED = -1;
 
     // Lock ensuring that concurrent manipulations of the event buffer are correct.
@@ -160,9 +162,15 @@
             initBuffer();
         }
 
+        final List<IpConnectivityEvent> protoEvents = IpConnectivityEventBuilder.toProto(events);
+
+        if (mNetdListener != null) {
+            mNetdListener.flushStatistics(protoEvents);
+        }
+
         final byte[] data;
         try {
-            data = IpConnectivityEventBuilder.serialize(dropped, events);
+            data = IpConnectivityEventBuilder.serialize(dropped, protoEvents);
         } catch (IOException e) {
             Log.e(TAG, "could not serialize events", e);
             return "";
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index 74a1f4f..f555f08 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -19,25 +19,28 @@
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
-import android.net.Network;
 import android.net.INetdEventCallback;
+import android.net.Network;
 import android.net.NetworkRequest;
+import android.net.metrics.ConnectStats;
 import android.net.metrics.DnsEvent;
-import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.INetdEventListener;
+import android.net.metrics.IpConnectivityLog;
 import android.os.RemoteException;
+import android.text.format.DateUtils;
 import android.util.Log;
-
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IndentingPrintWriter;
-
+import com.android.internal.util.TokenBucket;
+import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.ConnectStatistics;
+import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
 import java.io.PrintWriter;
 import java.util.Arrays;
+import java.util.List;
 import java.util.SortedMap;
 import java.util.TreeMap;
 
-
 /**
  * Implementation of the INetdEventListener interface.
  */
@@ -52,6 +55,12 @@
     // TODO: read this constant from system property
     private static final int MAX_LOOKUPS_PER_DNS_EVENT = 100;
 
+    // Rate limit connect latency logging to 1 measurement per 15 seconds (5760 / day) with maximum
+    // bursts of 5000 measurements.
+    private static final int CONNECT_LATENCY_BURST_LIMIT  = 5000;
+    private static final int CONNECT_LATENCY_FILL_RATE    = 15 * (int) DateUtils.SECOND_IN_MILLIS;
+    private static final int CONNECT_LATENCY_MAXIMUM_RECORDS = 20000;
+
     // 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.
@@ -121,6 +130,12 @@
         }
     };
 
+    @GuardedBy("this")
+    private final TokenBucket mConnectTb =
+            new TokenBucket(CONNECT_LATENCY_FILL_RATE, CONNECT_LATENCY_BURST_LIMIT);
+    @GuardedBy("this")
+    private ConnectStats mConnectStats = makeConnectStats();
+
     // Callback should only be registered/unregistered when logging is being enabled/disabled in DPM
     // by the device owner. It's DevicePolicyManager's responsibility to ensure that.
     @GuardedBy("this")
@@ -173,15 +188,30 @@
     @Override
     // Called concurrently by multiple binder threads.
     // This method must not block or perform long-running operations.
-    public synchronized void onConnectEvent(int netId, int error, int latencyMs, String ipAddr, int port,
-            int uid) throws RemoteException {
+    public synchronized void onConnectEvent(int netId, int error, int latencyMs, String ipAddr,
+            int port, int uid) throws RemoteException {
         maybeVerboseLog("onConnectEvent(%d, %d, %dms)", netId, error, latencyMs);
 
+        mConnectStats.addEvent(error, latencyMs, ipAddr);
+
         if (mNetdEventCallback != null) {
             mNetdEventCallback.onConnectEvent(ipAddr, port, System.currentTimeMillis(), uid);
         }
     }
 
+    public synchronized void flushStatistics(List<IpConnectivityEvent> events) {
+        events.add(flushConnectStats());
+        // TODO: migrate DnsEventBatch to IpConnectivityLogClass.DNSLatencies
+    }
+
+    private IpConnectivityEvent flushConnectStats() {
+        IpConnectivityEvent ev = new IpConnectivityEvent();
+        ev.setConnectStatistics(mConnectStats.toProto());
+        // TODO: add transport information
+        mConnectStats = makeConnectStats();
+        return ev;
+    }
+
     public synchronized void dump(PrintWriter writer) {
         IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
         pw.println(TAG + ":");
@@ -189,9 +219,14 @@
         for (DnsEventBatch batch : mEventBatches.values()) {
             pw.println(batch.toString());
         }
+        // TODO: also dump ConnectStats
         pw.decreaseIndent();
     }
 
+    private ConnectStats makeConnectStats() {
+        return new ConnectStats(mConnectTb, CONNECT_LATENCY_MAXIMUM_RECORDS);
+    }
+
     private static void maybeLog(String s, Object... args) {
         if (DBG) Log.d(TAG, String.format(s, args));
     }
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index c6bf4c5..63b5250 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -19,7 +19,6 @@
 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;
@@ -27,17 +26,40 @@
 import android.os.UserHandle;
 import android.telephony.TelephonyManager;
 import android.util.Slog;
-
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.widget.Toast;
 import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
-import static android.net.NetworkCapabilities.*;
-
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 
 public class NetworkNotificationManager {
 
-    public static enum NotificationType { SIGN_IN, NO_INTERNET, LOST_INTERNET, NETWORK_SWITCH };
+    public static enum NotificationType {
+        LOST_INTERNET(MetricsEvent.NOTIFICATION_NETWORK_LOST_INTERNET),
+        NETWORK_SWITCH(MetricsEvent.NOTIFICATION_NETWORK_SWITCH),
+        NO_INTERNET(MetricsEvent.NOTIFICATION_NETWORK_NO_INTERNET),
+        SIGN_IN(MetricsEvent.NOTIFICATION_NETWORK_SIGN_IN);
 
-    private static final String NOTIFICATION_ID = "Connectivity.Notification";
+        public final int eventId;
+
+        NotificationType(int eventId) {
+            this.eventId = eventId;
+            Holder.sIdToTypeMap.put(eventId, this);
+        }
+
+        private static class Holder {
+            private static SparseArray<NotificationType> sIdToTypeMap = new SparseArray<>();
+        }
+
+        public static NotificationType getFromId(int id) {
+            return Holder.sIdToTypeMap.get(id);
+        }
+    };
 
     private static final String TAG = NetworkNotificationManager.class.getSimpleName();
     private static final boolean DBG = true;
@@ -46,11 +68,14 @@
     private final Context mContext;
     private final TelephonyManager mTelephonyManager;
     private final NotificationManager mNotificationManager;
+    // Tracks the types of notifications managed by this instance, from creation to cancellation.
+    private final SparseIntArray mNotificationTypeMap;
 
     public NetworkNotificationManager(Context c, TelephonyManager t, NotificationManager n) {
         mContext = c;
         mTelephonyManager = t;
         mNotificationManager = n;
+        mNotificationTypeMap = new SparseIntArray();
     }
 
     // TODO: deal more gracefully with multi-transport networks.
@@ -100,8 +125,10 @@
      */
     public void showNotification(int id, NotificationType notifyType, NetworkAgentInfo nai,
             NetworkAgentInfo switchToNai, PendingIntent intent, boolean highPriority) {
-        int transportType;
-        String extraInfo;
+        final String tag = tagFor(id);
+        final int eventId = notifyType.eventId;
+        final int transportType;
+        final String extraInfo;
         if (nai != null) {
             transportType = getFirstTransportType(nai);
             extraInfo = nai.networkInfo.getExtraInfo();
@@ -114,9 +141,9 @@
         }
 
         if (DBG) {
-            Slog.d(TAG, "showNotification id=" + id + " " + notifyType
-                    + " transportType=" + getTransportName(transportType)
-                    + " extraInfo=" + extraInfo + " highPriority=" + highPriority);
+            Slog.d(TAG, String.format(
+                    "showNotification tag=%s event=%s transport=%s extraInfo=%d highPrioriy=%s",
+                    tag, nameOf(eventId), getTransportName(transportType), extraInfo, highPriority));
         }
 
         Resources r = Resources.getSystem();
@@ -184,22 +211,31 @@
 
         Notification notification = builder.build();
 
+        mNotificationTypeMap.put(id, eventId);
         try {
-            mNotificationManager.notifyAsUser(NOTIFICATION_ID, id, notification, UserHandle.ALL);
+            mNotificationManager.notifyAsUser(tag, eventId, notification, UserHandle.ALL);
         } catch (NullPointerException npe) {
             Slog.d(TAG, "setNotificationVisible: visible notificationManager error", npe);
         }
     }
 
     public void clearNotification(int id) {
+        final String tag = tagFor(id);
+        if (mNotificationTypeMap.indexOfKey(id) < 0) {
+            Slog.e(TAG, "cannot clear unknown notification with tag=" + tag);
+            return;
+        }
+        final int eventId = mNotificationTypeMap.get(id);
         if (DBG) {
-            Slog.d(TAG, "clearNotification id=" + id);
+            Slog.d(TAG, String.format("clearing notification tag=%s event=", tag, nameOf(eventId)));
         }
         try {
-            mNotificationManager.cancelAsUser(NOTIFICATION_ID, id, UserHandle.ALL);
+            mNotificationManager.cancelAsUser(tag, eventId, UserHandle.ALL);
         } catch (NullPointerException npe) {
-            Slog.d(TAG, "setNotificationVisible: cancel notificationManager error", npe);
+            Slog.d(TAG, String.format(
+                    "failed to clear notification tag=%s event=", tag, nameOf(eventId)), npe);
         }
+        mNotificationTypeMap.delete(id);
     }
 
     /**
@@ -222,4 +258,15 @@
                 R.string.network_switch_metered_toast, fromTransport, toTransport);
         Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
     }
+
+    @VisibleForTesting
+    static String tagFor(int id) {
+        return String.format("ConnectivityNotification:%d", id);
+    }
+
+    @VisibleForTesting
+    static String nameOf(int eventId) {
+        NotificationType t = NotificationType.getFromId(eventId);
+        return (t != null) ? t.name() : "UNKNOWN";
+    }
 }
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 132967c..3f0ebf2 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -46,7 +46,11 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.service.fingerprint.FingerprintActionStatsProto;
+import android.service.fingerprint.FingerprintServiceDumpProto;
+import android.service.fingerprint.FingerprintUserStatsProto;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.MetricsLogger;
@@ -968,7 +972,11 @@
 
             final long ident = Binder.clearCallingIdentity();
             try {
-                dumpInternal(pw);
+                if (args.length > 0 && "--proto".equals(args[0])) {
+                    dumpProto(fd);
+                } else {
+                    dumpInternal(pw);
+                }
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -1027,6 +1035,45 @@
         pw.println(dump);
     }
 
+    private void dumpProto(FileDescriptor fd) {
+        final ProtoOutputStream proto = new ProtoOutputStream(fd);
+        for (UserInfo user : UserManager.get(getContext()).getUsers()) {
+            final int userId = user.getUserHandle().getIdentifier();
+
+            final long userToken = proto.start(FingerprintServiceDumpProto.USERS);
+
+            proto.write(FingerprintUserStatsProto.USER_ID, userId);
+            proto.write(FingerprintUserStatsProto.NUM_FINGERPRINTS,
+                    mFingerprintUtils.getFingerprintsForUser(mContext, userId).size());
+
+            // Normal fingerprint authentications (e.g. lockscreen)
+            final PerformanceStats normal = mPerformanceMap.get(userId);
+            if (normal != null) {
+                final long countsToken = proto.start(FingerprintUserStatsProto.NORMAL);
+                proto.write(FingerprintActionStatsProto.ACCEPT, normal.accept);
+                proto.write(FingerprintActionStatsProto.REJECT, normal.reject);
+                proto.write(FingerprintActionStatsProto.ACQUIRE, normal.acquire);
+                proto.write(FingerprintActionStatsProto.LOCKOUT, normal.lockout);
+                proto.end(countsToken);
+            }
+
+            // Statistics about secure fingerprint transactions (e.g. to unlock password
+            // storage, make secure purchases, etc.)
+            final PerformanceStats crypto = mPerformanceMap.get(userId);
+            if (crypto != null) {
+                final long countsToken = proto.start(FingerprintUserStatsProto.CRYPTO);
+                proto.write(FingerprintActionStatsProto.ACCEPT, crypto.accept);
+                proto.write(FingerprintActionStatsProto.REJECT, crypto.reject);
+                proto.write(FingerprintActionStatsProto.ACQUIRE, crypto.acquire);
+                proto.write(FingerprintActionStatsProto.LOCKOUT, crypto.lockout);
+                proto.end(countsToken);
+            }
+
+            proto.end(userToken);
+        }
+        proto.flush();
+    }
+
     @Override
     public void onStart() {
         publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 44aafa8..e5f4282 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -888,13 +888,42 @@
     }
 
     /**
-     * Send a key event to other device.
+     * Send a key event to other CEC device. The logical address of target device will be given by
+     * {@link #findKeyReceiverAddress}.
      *
      * @param keyCode key code defined in {@link android.view.KeyEvent}
      * @param isPressed {@code true} for key down event
+     * @see #findKeyReceiverAddress()
      */
+    @ServiceThreadOnly
     protected void sendKeyEvent(int keyCode, boolean isPressed) {
-        Slog.w(TAG, "sendKeyEvent not implemented");
+        assertRunOnServiceThread();
+        if (!HdmiCecKeycode.isSupportedKeycode(keyCode)) {
+            Slog.w(TAG, "Unsupported key: " + keyCode);
+            return;
+        }
+        List<SendKeyAction> action = getActions(SendKeyAction.class);
+        int logicalAddress = findKeyReceiverAddress();
+        if (logicalAddress == Constants.ADDR_INVALID || logicalAddress == mAddress) {
+            // Don't send key event to invalid device or itself.
+            Slog.w(TAG, "Discard key event: " + keyCode + ", pressed:" + isPressed
+                    + ", receiverAddr=" + logicalAddress);
+        } else if (!action.isEmpty()) {
+            action.get(0).processKeyEvent(keyCode, isPressed);
+        } else if (isPressed) {
+            addAndStartAction(new SendKeyAction(this, logicalAddress, keyCode));
+        }
+    }
+
+    /**
+     * Returns the logical address of the device which will receive key events via
+     * {@link #sendKeyEvent}.
+     *
+     * @see #sendKeyEvent(int, boolean)
+     */
+    protected int findKeyReceiverAddress() {
+        Slog.w(TAG, "findKeyReceiverAddress is not implemented");
+        return Constants.ADDR_INVALID;
     }
 
     void sendUserControlPressedAndReleased(int targetAddress, int cecKeycode) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 69c012e..d45b00b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -355,6 +355,11 @@
     }
 
     @Override
+    protected int findKeyReceiverAddress() {
+        return Constants.ADDR_TV;
+    }
+
+    @Override
     @ServiceThreadOnly
     protected void sendStandby(int deviceId) {
         assertRunOnServiceThread();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index c85d979..4526ab74 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -432,40 +432,8 @@
         return mService.getPowerStatus();
     }
 
-    /**
-     * Sends key to a target CEC device.
-     *
-     * @param keyCode key code to send. Defined in {@link android.view.KeyEvent}.
-     * @param isPressed true if this is key press event
-     */
     @Override
-    @ServiceThreadOnly
-    protected void sendKeyEvent(int keyCode, boolean isPressed) {
-        assertRunOnServiceThread();
-        if (!HdmiCecKeycode.isSupportedKeycode(keyCode)) {
-            Slog.w(TAG, "Unsupported key: " + keyCode);
-            return;
-        }
-        List<SendKeyAction> action = getActions(SendKeyAction.class);
-        int logicalAddress = findKeyReceiverAddress();
-        if (logicalAddress == mAddress) {
-            Slog.w(TAG, "Discard key event to itself :" + keyCode + " pressed:" + isPressed);
-            return;
-        }
-        if (!action.isEmpty()) {
-            action.get(0).processKeyEvent(keyCode, isPressed);
-        } else {
-            if (isPressed) {
-                if (logicalAddress != Constants.ADDR_INVALID) {
-                    addAndStartAction(new SendKeyAction(this, logicalAddress, keyCode));
-                    return;
-                }
-            }
-            Slog.w(TAG, "Discard key event: " + keyCode + " pressed:" + isPressed);
-        }
-    }
-
-    private int findKeyReceiverAddress() {
+    protected int findKeyReceiverAddress() {
         if (getActiveSource().isValid()) {
             return getActiveSource().logicalAddress;
         }
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 54366e6..fb2b961 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -457,6 +457,8 @@
             if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
                 xtraDownloadRequest();
             }
+            // Always on, notify HAL so it can get data it needs
+            sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
         }
     };
 
@@ -469,6 +471,7 @@
             new ConnectivityManager.NetworkCallback() {
         @Override
         public void onAvailable(Network network) {
+            // Specific to a change to a SUPL enabled network becoming ready
             sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
         }
 
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 8ca6086..386e78b 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -553,15 +553,21 @@
             @Override
             public NetworkStats getSummaryForAllUid(
                     NetworkTemplate template, long start, long end, boolean includeTags) {
-                @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage);
-                final NetworkStats stats =
-                        getUidComplete().getSummary(template, start, end, accessLevel);
-                if (includeTags) {
-                    final NetworkStats tagStats = getUidTagComplete()
-                            .getSummary(template, start, end, accessLevel);
-                    stats.combineAllValues(tagStats);
+                try {
+                    @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage);
+                    final NetworkStats stats =
+                            getUidComplete().getSummary(template, start, end, accessLevel);
+                    if (includeTags) {
+                        final NetworkStats tagStats = getUidTagComplete()
+                                .getSummary(template, start, end, accessLevel);
+                        stats.combineAllValues(tagStats);
+                    }
+                    return stats;
+                } catch (NullPointerException e) {
+                    // TODO: Track down and fix the cause of this crash and remove this catch block.
+                    Slog.wtf(TAG, "NullPointerException in getSummaryForAllUid", e);
+                    throw e;
                 }
-                return stats;
             }
 
             @Override
diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java
index 7dff2c1..1e0035d 100644
--- a/services/core/java/com/android/server/notification/NotificationComparator.java
+++ b/services/core/java/com/android/server/notification/NotificationComparator.java
@@ -15,7 +15,25 @@
  */
 package com.android.server.notification;
 
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.telecom.TelecomManager;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Slog;
+
 import java.util.Comparator;
+import java.util.Objects;
 
 /**
  * Sorts notifications individually into attention-relevant order.
@@ -23,8 +41,45 @@
 public class NotificationComparator
         implements Comparator<NotificationRecord> {
 
+    private final String DEFAULT_SMS_APP_SETTING = Settings.Secure.SMS_DEFAULT_APPLICATION;
+
+    private final Context mContext;
+    private String mDefaultPhoneApp;
+    private ArrayMap<Integer, String> mDefaultSmsApp = new ArrayMap<>();
+
+    public NotificationComparator(Context context) {
+        mContext = context;
+        mContext.registerReceiver(mPhoneAppBroadcastReceiver,
+                new IntentFilter(TelecomManager.ACTION_DEFAULT_DIALER_CHANGED));
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(DEFAULT_SMS_APP_SETTING), false, mSmsContentObserver);
+    }
+
     @Override
     public int compare(NotificationRecord left, NotificationRecord right) {
+        // First up: sufficiently important ongoing notifications of certain categories
+        boolean leftImportantOngoing = isImportantOngoing(left);
+        boolean rightImportantOngoing = isImportantOngoing(right);
+
+        if (leftImportantOngoing != rightImportantOngoing) {
+            // by ongoing, ongoing higher than non-ongoing
+            return -1 * Boolean.compare(leftImportantOngoing, rightImportantOngoing);
+        }
+
+        // Next: sufficiently import person to person communication
+        boolean leftPeople = isImportantMessaging(left);
+        boolean rightPeople = isImportantMessaging(right);
+
+        if (leftPeople && rightPeople){
+            // by contact proximity, close to far. if same proximity, check further fields.
+            if (Float.compare(left.getContactAffinity(), right.getContactAffinity()) != 0) {
+                return -1 * Float.compare(left.getContactAffinity(), right.getContactAffinity());
+            }
+        } else if (leftPeople != rightPeople) {
+            // People, messaging higher than non-messaging
+            return -1 * Boolean.compare(leftPeople, rightPeople);
+        }
+
         final int leftImportance = left.getImportance();
         final int rightImportance = right.getImportance();
         if (leftImportance != rightImportance) {
@@ -47,14 +102,112 @@
             return -1 * Integer.compare(leftPriority, rightPriority);
         }
 
-        final float leftPeople = left.getContactAffinity();
-        final float rightPeople = right.getContactAffinity();
-        if (leftPeople != rightPeople) {
-            // by contact proximity, close to far
-            return -1 * Float.compare(leftPeople, rightPeople);
-        }
-
         // then break ties by time, most recent first
         return -1 * Long.compare(left.getRankingTimeMs(), right.getRankingTimeMs());
     }
+
+    private boolean isImportantOngoing(NotificationRecord record) {
+        if (!isOngoing(record)) {
+            return false;
+        }
+
+        if (record.getImportance() < NotificationManager.IMPORTANCE_LOW) {
+            return false;
+        }
+
+        // TODO: add whitelist
+
+        return isCall(record) || isMediaNotification(record);
+    }
+
+    protected boolean isImportantMessaging(NotificationRecord record) {
+        if (record.getImportance() < NotificationManager.IMPORTANCE_LOW) {
+            return false;
+        }
+
+        Class<? extends Notification.Style> style = getNotificationStyle(record);
+        if (Notification.MessagingStyle.class.equals(style)) {
+            return true;
+        }
+
+        if (record.getContactAffinity() > ValidateNotificationPeople.NONE) {
+            return true;
+        }
+
+        if (record.getNotification().category == Notification.CATEGORY_MESSAGE
+                && isDefaultMessagingApp(record)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    private boolean isOngoing(NotificationRecord record) {
+        final int ongoingFlags =
+                Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_ONGOING_EVENT;
+        return (record.getNotification().flags & ongoingFlags) != 0;
+    }
+
+
+    private Class<? extends Notification.Style> getNotificationStyle(NotificationRecord record) {
+        String templateClass =
+                record.getNotification().extras.getString(Notification.EXTRA_TEMPLATE);
+
+        if (!TextUtils.isEmpty(templateClass)) {
+            return Notification.getNotificationStyleClass(templateClass);
+        }
+        return null;
+    }
+
+    private boolean isMediaNotification(NotificationRecord record) {
+        return record.getNotification().extras.getParcelable(
+                Notification.EXTRA_MEDIA_SESSION) != null;
+    }
+
+    private boolean isCall(NotificationRecord record) {
+        return record.getNotification().category == Notification.CATEGORY_CALL
+                && isDefaultPhoneApp(record.sbn.getPackageName());
+    }
+
+    private boolean isDefaultPhoneApp(String pkg) {
+        if (mDefaultPhoneApp == null) {
+            final TelecomManager telecomm =
+                    (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
+            mDefaultPhoneApp = telecomm != null ? telecomm.getDefaultDialerPackage() : null;
+        }
+        return Objects.equals(pkg, mDefaultPhoneApp);
+    }
+
+    @SuppressWarnings("deprecation")
+    private boolean isDefaultMessagingApp(NotificationRecord record) {
+        final int userId = record.getUserId();
+        if (userId == UserHandle.USER_NULL || userId == UserHandle.USER_ALL) return false;
+        if (mDefaultSmsApp.get(userId) == null) {
+            mDefaultSmsApp.put(userId, Settings.Secure.getStringForUser(
+                    mContext.getContentResolver(),
+                    Settings.Secure.SMS_DEFAULT_APPLICATION, userId));
+        }
+        return Objects.equals(mDefaultSmsApp.get(userId), record.sbn.getPackageName());
+    }
+
+    private final BroadcastReceiver mPhoneAppBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            mDefaultPhoneApp =
+                    intent.getStringExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME);
+        }
+    };
+
+    private final ContentObserver mSmsContentObserver = new ContentObserver(
+            new Handler(Looper.getMainLooper())) {
+        @Override
+        public void onChange(boolean selfChange, Uri uri, int userId) {
+            if (Settings.Secure.getUriFor(DEFAULT_SMS_APP_SETTING).equals(uri)) {
+                mDefaultSmsApp.put(userId, Settings.Secure.getStringForUser(
+                        mContext.getContentResolver(),
+                        Settings.Secure.SMS_DEFAULT_APPLICATION, userId));
+
+            }
+        }
+    };
 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index f58522b5..a6fb458 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1552,9 +1552,6 @@
         @Override
         public void createNotificationChannel(String pkg, NotificationChannel channel,
                 IOnNotificationChannelCreatedListener listener) throws RemoteException {
-            Preconditions.checkNotNull(channel);
-            Preconditions.checkNotNull(channel.getId());
-            Preconditions.checkNotNull(channel.getName());
             checkCallerIsSystemOrSameApp(pkg);
             mRankingHelper.createNotificationChannel(pkg, Binder.getCallingUid(), channel);
             savePolicyFile();
@@ -1563,7 +1560,6 @@
 
         @Override
         public NotificationChannel getNotificationChannel(String pkg, String channelId) {
-            Preconditions.checkNotNull(channelId);
             checkCallerIsSystemOrSameApp(pkg);
             return mRankingHelper.getNotificationChannel(pkg, Binder.getCallingUid(), channelId);
         }
@@ -1571,14 +1567,12 @@
         @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");
@@ -1592,8 +1586,6 @@
         @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
@@ -2383,7 +2375,7 @@
         }
 
         @Override
-        public void applyAdjustmentFromAssistantService(INotificationListener token,
+        public void applyAdjustmentFromAssistant(INotificationListener token,
                 Adjustment adjustment) throws RemoteException {
             final long identity = Binder.clearCallingIdentity();
             try {
@@ -2398,7 +2390,7 @@
         }
 
         @Override
-        public void applyAdjustmentsFromAssistantService(INotificationListener token,
+        public void applyAdjustmentsFromAssistant(INotificationListener token,
                 List<Adjustment> adjustments) throws RemoteException {
 
             final long identity = Binder.clearCallingIdentity();
@@ -2414,6 +2406,52 @@
                 Binder.restoreCallingIdentity(identity);
             }
         }
+
+        @Override
+        public void createNotificationChannelFromAssistant(INotificationListener token, String pkg,
+                NotificationChannel channel) throws RemoteException {
+            ManagedServiceInfo info = mNotificationAssistants.checkServiceTokenLocked(token);
+            int uid = mPackageManager.getPackageUid(pkg, 0, info.userid);
+            mRankingHelper.createNotificationChannel(pkg, uid, channel);
+            savePolicyFile();
+        }
+
+        @Override
+        public void deleteNotificationChannelFromAssistant(INotificationListener token, String pkg,
+                String channelId) throws RemoteException {
+            ManagedServiceInfo info = mNotificationAssistants.checkServiceTokenLocked(token);
+            if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
+                throw new IllegalArgumentException("Cannot delete default channel");
+            }
+
+            int uid = mPackageManager.getPackageUid(pkg, 0, info.userid);
+            cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
+                    info.userid, REASON_CHANNEL_BANNED, null);
+            mRankingHelper.deleteNotificationChannel(pkg, uid, channelId);
+            savePolicyFile();
+        }
+
+        @Override
+        public void updateNotificationChannelFromAssistant(INotificationListener token, String pkg,
+                NotificationChannel channel) throws RemoteException {
+            ManagedServiceInfo info = mNotificationAssistants.checkServiceTokenLocked(token);
+            if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
+                // cancel
+                cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
+                        info.userid, REASON_CHANNEL_BANNED, null);
+            }
+            int uid = mPackageManager.getPackageUid(pkg, 0, info.userid);
+            mRankingHelper.updateNotificationChannelFromAssistant(pkg, uid, channel);
+            savePolicyFile();
+        }
+
+        @Override
+        public ParceledListSlice<NotificationChannel> getNotificationChannelsFromAssistant(
+                INotificationListener token, String pkg) throws RemoteException {
+            ManagedServiceInfo info = mNotificationAssistants.checkServiceTokenLocked(token);
+            int uid = mPackageManager.getPackageUid(pkg, 0, info.userid);
+            return mRankingHelper.getNotificationChannels(pkg, uid);
+        }
     };
 
     private void applyAdjustmentLocked(Adjustment adjustment) {
@@ -3924,7 +3962,7 @@
         }
     }
 
-    private static boolean isUidSystem(int uid) {
+    protected static boolean isUidSystem(int uid) {
         final int appid = UserHandle.getAppId(uid);
         return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
     }
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 4fcc987..a03c4aa 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -136,6 +136,12 @@
     private boolean isPreChannelsNotification() {
         try {
             if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(getChannel().getId())) {
+                final boolean isSystemNotification =
+                        NotificationManagerService.isUidSystem(sbn.getUid())
+                                || ("android".equals(sbn.getPackageName()));
+                if (isSystemNotification) {
+                    return false;
+                }
                 final ApplicationInfo applicationInfo =
                         mContext.getPackageManager().getApplicationInfoAsUser(sbn.getPackageName(),
                                 0, sbn.getUserId());
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index cb5fb0d..882e84c 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -34,7 +34,7 @@
 
     void createNotificationChannel(String pkg, int uid, NotificationChannel channel);
     void updateNotificationChannel(String pkg, int uid, NotificationChannel channel);
-    void updateNotificationChannelFromRanker(String pkg, int uid, NotificationChannel channel);
+    void updateNotificationChannelFromAssistant(String pkg, int uid, NotificationChannel channel);
     NotificationChannel getNotificationChannel(String pkg, int uid, String channelId);
     NotificationChannel getNotificationChannelWithFallback(String pkg, int uid, String channelId);
     void deleteNotificationChannel(String pkg, int uid, String channelId);
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 5073b1b..95718de 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -18,6 +18,7 @@
 import static android.app.NotificationManager.IMPORTANCE_NONE;
 
 import com.android.internal.R;
+import com.android.internal.util.Preconditions;
 
 import android.app.Notification;
 import android.app.NotificationChannel;
@@ -72,7 +73,7 @@
     private static final int DEFAULT_IMPORTANCE = NotificationManager.IMPORTANCE_UNSPECIFIED;
 
     private final NotificationSignalExtractor[] mSignalExtractors;
-    private final NotificationComparator mPreliminaryComparator = new NotificationComparator();
+    private final NotificationComparator mPreliminaryComparator;
     private final GlobalSortKeyComparator mFinalComparator = new GlobalSortKeyComparator();
 
     private final ArrayMap<String, Record> mRecords = new ArrayMap<>(); // pkg|uid => Record
@@ -89,6 +90,8 @@
         mRankingHandler = rankingHandler;
         mPm = pm;
 
+        mPreliminaryComparator = new NotificationComparator(mContext);
+
         final int N = extractorNames.length;
         mSignalExtractors = new NotificationSignalExtractor[N];
         for (int i = 0; i < N; i++) {
@@ -451,7 +454,14 @@
 
     @Override
     public void createNotificationChannel(String pkg, int uid, NotificationChannel channel) {
+        Preconditions.checkNotNull(pkg);
+        Preconditions.checkNotNull(channel);
+        Preconditions.checkNotNull(channel.getId());
+        Preconditions.checkNotNull(channel.getName());
         Record r = getOrCreateRecord(pkg, uid);
+        if (r == null) {
+            throw new IllegalArgumentException("Invalid package");
+        }
         if (IMPORTANCE_NONE == r.importance) {
             throw new IllegalArgumentException("Package blocked");
         }
@@ -472,7 +482,12 @@
 
     @Override
     public void updateNotificationChannel(String pkg, int uid, NotificationChannel updatedChannel) {
+        Preconditions.checkNotNull(updatedChannel);
+        Preconditions.checkNotNull(updatedChannel.getId());
         Record r = getOrCreateRecord(pkg, uid);
+        if (r == null) {
+            throw new IllegalArgumentException("Invalid package");
+        }
         NotificationChannel channel = r.channels.get(updatedChannel.getId());
         if (channel == null) {
             throw new IllegalArgumentException("Channel does not exist");
@@ -485,9 +500,12 @@
     }
 
     @Override
-    public void updateNotificationChannelFromRanker(String pkg, int uid,
+    public void updateNotificationChannelFromAssistant(String pkg, int uid,
             NotificationChannel updatedChannel) {
         Record r = getOrCreateRecord(pkg, uid);
+        if (r == null) {
+            throw new IllegalArgumentException("Invalid package");
+        }
         NotificationChannel channel = r.channels.get(updatedChannel.getId());
         if (channel == null) {
             throw new IllegalArgumentException("Channel does not exist");
@@ -538,7 +556,11 @@
 
     @Override
     public NotificationChannel getNotificationChannel(String pkg, int uid, String channelId) {
+        Preconditions.checkNotNull(pkg);
         Record r = getOrCreateRecord(pkg, uid);
+        if (r == null) {
+            throw new IllegalArgumentException("Invalid package");
+        }
         if (channelId == null) {
             channelId = NotificationChannel.DEFAULT_CHANNEL_ID;
         }
@@ -547,7 +569,12 @@
 
     @Override
     public void deleteNotificationChannel(String pkg, int uid, String channelId) {
+        Preconditions.checkNotNull(pkg);
+        Preconditions.checkNotNull(channelId);
         Record r = getRecord(pkg, uid);
+        if (r == null) {
+            throw new IllegalArgumentException("Invalid package");
+        }
         if (r != null) {
             r.channels.remove(channelId);
         }
@@ -555,8 +582,12 @@
 
     @Override
     public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid) {
+        Preconditions.checkNotNull(pkg);
         List<NotificationChannel> channels = new ArrayList<>();
-        Record r = getOrCreateRecord(pkg, uid);
+        Record r = getRecord(pkg, uid);
+        if (r == null) {
+            throw new IllegalArgumentException("Invalid package");
+        }
         int N = r.channels.size();
         for (int i = 0; i < N; i++) {
             channels.add(r.channels.valueAt(i));
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f7cccc8..34c1470 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -5524,9 +5524,21 @@
             final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
             final ActivityInfo ai = getActivityInfo(comp, flags, userId);
             if (ai != null) {
-                final ResolveInfo ri = new ResolveInfo();
-                ri.activityInfo = ai;
-                list.add(ri);
+                // When specifying an explicit component, we prevent the activity from being
+                // used when either 1) the calling package is normal and the activity is within
+                // an ephemeral application or 2) the calling package is ephemeral and the
+                // activity is not visible to ephemeral applications.
+                boolean blockResolution =
+                        (ephemeralPkgName == null
+                                && (ai.applicationInfo.privateFlags
+                                        & ApplicationInfo.PRIVATE_FLAG_EPHEMERAL) != 0)
+                        || (ephemeralPkgName != null
+                                && (ai.flags & ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL) == 0);
+                if (!blockResolution) {
+                    final ResolveInfo ri = new ResolveInfo();
+                    ri.activityInfo = ai;
+                    list.add(ri);
+                }
             }
             return list;
         }
@@ -5604,10 +5616,10 @@
             } else {
                 final PackageParser.Package pkg = mPackages.get(pkgName);
                 if (pkg != null) {
-                    result = filterIfNotSystemUser(
+                    result = filterForEphemeral(filterIfNotSystemUser(
                             mActivities.queryIntentForPackage(
                                     intent, resolvedType, flags, pkg.activities, userId),
-                            userId);
+                            userId), ephemeralPkgName);
                 } else {
                     // the caller wants to resolve for a particular package; however, there
                     // were no installed results, so, try to find an ephemeral result
@@ -7587,19 +7599,6 @@
                 compilerFilter = getNonProfileGuidedCompilerFilter(compilerFilter);
             }
 
-            // 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);
-            }
-
             // checkProfiles is false to avoid merging profiles during boot which
             // might interfere with background compilation (b/28612421).
             // Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index 442a4f4..9222917 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -59,8 +59,9 @@
     private static List<Policy> sPolicies = new ArrayList<>();
 
     /** Path to MAC permissions on system image */
-    private static final File MAC_PERMISSIONS = new File(Environment.getRootDirectory(),
-            "/etc/security/mac_permissions.xml");
+    private static final File[] MAC_PERMISSIONS =
+    { new File(Environment.getRootDirectory(), "/etc/security/plat_mac_permissions.xml"),
+      new File(Environment.getRootDirectory(), "/etc/security/nonplat_mac_permissions.xml") };
 
     // Append privapp to existing seinfo label
     private static final String PRIVILEGED_APP_STR = ":privapp";
@@ -87,49 +88,51 @@
 
         FileReader policyFile = null;
         XmlPullParser parser = Xml.newPullParser();
-        try {
-            policyFile = new FileReader(MAC_PERMISSIONS);
-            Slog.d(TAG, "Using policy file " + MAC_PERMISSIONS);
+        for (int i = 0; i < MAC_PERMISSIONS.length; i++) {
+            try {
+                policyFile = new FileReader(MAC_PERMISSIONS[i]);
+                Slog.d(TAG, "Using policy file " + MAC_PERMISSIONS[i]);
 
-            parser.setInput(policyFile);
-            parser.nextTag();
-            parser.require(XmlPullParser.START_TAG, null, "policy");
+                parser.setInput(policyFile);
+                parser.nextTag();
+                parser.require(XmlPullParser.START_TAG, null, "policy");
 
-            while (parser.next() != XmlPullParser.END_TAG) {
-                if (parser.getEventType() != XmlPullParser.START_TAG) {
-                    continue;
+                while (parser.next() != XmlPullParser.END_TAG) {
+                    if (parser.getEventType() != XmlPullParser.START_TAG) {
+                        continue;
+                    }
+
+                    switch (parser.getName()) {
+                        case "signer":
+                            policies.add(readSignerOrThrow(parser));
+                            break;
+                        default:
+                            skip(parser);
+                    }
                 }
-
-                switch (parser.getName()) {
-                    case "signer":
-                        policies.add(readSignerOrThrow(parser));
-                        break;
-                    default:
-                        skip(parser);
-                }
+            } catch (IllegalStateException | IllegalArgumentException |
+                     XmlPullParserException ex) {
+                StringBuilder sb = new StringBuilder("Exception @");
+                sb.append(parser.getPositionDescription());
+                sb.append(" while parsing ");
+                sb.append(MAC_PERMISSIONS[i]);
+                sb.append(":");
+                sb.append(ex);
+                Slog.w(TAG, sb.toString());
+                return false;
+            } catch (IOException ioe) {
+                Slog.w(TAG, "Exception parsing " + MAC_PERMISSIONS[i], ioe);
+                return false;
+            } finally {
+                IoUtils.closeQuietly(policyFile);
             }
-        } catch (IllegalStateException | IllegalArgumentException |
-                XmlPullParserException ex) {
-            StringBuilder sb = new StringBuilder("Exception @");
-            sb.append(parser.getPositionDescription());
-            sb.append(" while parsing ");
-            sb.append(MAC_PERMISSIONS);
-            sb.append(":");
-            sb.append(ex);
-            Slog.w(TAG, sb.toString());
-            return false;
-        } catch (IOException ioe) {
-            Slog.w(TAG, "Exception parsing " + MAC_PERMISSIONS, ioe);
-            return false;
-        } finally {
-            IoUtils.closeQuietly(policyFile);
         }
 
         // Now sort the policy stanzas
         PolicyComparator policySort = new PolicyComparator();
         Collections.sort(policies, policySort);
         if (policySort.foundDuplicate()) {
-            Slog.w(TAG, "ERROR! Duplicate entries found parsing " + MAC_PERMISSIONS);
+            Slog.w(TAG, "ERROR! Duplicate entries found parsing mac_permissions.xml files");
             return false;
         }
 
diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java
index 2af1bcb..3060840 100644
--- a/services/core/java/com/android/server/pm/ShortcutLauncher.java
+++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java
@@ -16,6 +16,7 @@
 package com.android.server.pm;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.content.pm.PackageInfo;
 import android.content.pm.ShortcutInfo;
@@ -103,6 +104,9 @@
         // Nothing to do.
     }
 
+    /**
+     * Pin the given shortcuts, replacing the current pinned ones.
+     */
     public void pinShortcuts(@UserIdInt int packageUserId,
             @NonNull String packageName, @NonNull List<String> ids) {
         final ShortcutPackage packageShortcuts =
@@ -143,11 +147,39 @@
     /**
      * Return the pinned shortcut IDs for the publisher package.
      */
+    @Nullable
     public ArraySet<String> getPinnedShortcutIds(@NonNull String packageName,
             @UserIdInt int packageUserId) {
         return mPinnedShortcuts.get(PackageWithUser.of(packageUserId, packageName));
     }
 
+    /**
+     * Return true if the given shortcut is pinned by this launcher.
+     */
+    public boolean hasPinned(ShortcutInfo shortcut) {
+        final ArraySet<String> pinned =
+                getPinnedShortcutIds(shortcut.getPackage(), shortcut.getUserId());
+        return (pinned != null) && pinned.contains(shortcut.getId());
+    }
+
+    /**
+     * Additionally pin a shortcut. c.f. {@link #pinShortcuts(int, String, List)}
+     */
+    public void addPinnedShortcut(@NonNull String packageName, @UserIdInt int packageUserId,
+            String id) {
+        final ArraySet<String> pinnedSet = getPinnedShortcutIds(packageName, packageUserId);
+        final ArrayList<String> pinnedList;
+        if (pinnedSet != null) {
+            pinnedList = new ArrayList<>(pinnedSet.size() + 1);
+            pinnedList.addAll(pinnedSet);
+        } else {
+            pinnedList = new ArrayList<>(1);
+        }
+        pinnedList.add(id);
+
+        pinShortcuts(packageUserId, packageName, pinnedList);
+    }
+
     boolean cleanUpPackage(String packageName, @UserIdInt int packageUserId) {
         return mPinnedShortcuts.remove(PackageWithUser.of(packageUserId, packageName)) != null;
     }
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 2eb0778..b745062 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -179,7 +179,7 @@
         }
     }
 
-    private void ensureNotImmutable(@NonNull String id) {
+    public void ensureNotImmutable(@NonNull String id) {
         ensureNotImmutable(mShortcuts.get(id));
     }
 
@@ -706,6 +706,7 @@
             for (int i = mShortcuts.size() - 1; i >= 0; i--) {
                 final ShortcutInfo si = mShortcuts.valueAt(i);
 
+                // Disable dynamic shortcuts whose target activity is gone.
                 if (si.isDynamic()) {
                     if (!s.injectIsMainActivity(si.getActivity(), getPackageUserId())) {
                         Slog.w(TAG, String.format(
diff --git a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
new file mode 100644
index 0000000..cdb69ce
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
@@ -0,0 +1,355 @@
+/*
+ * 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.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.content.pm.IPinItemRequest;
+import android.content.pm.LauncherApps;
+import android.content.pm.LauncherApps.PinItemRequest;
+import android.content.pm.ShortcutInfo;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Pair;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
+/**
+ * Handles {@link android.content.pm.ShortcutManager#requestPinShortcut} related tasks.
+ */
+class ShortcutRequestPinProcessor {
+    private static final String TAG = ShortcutService.TAG;
+    private static final boolean DEBUG = ShortcutService.DEBUG;
+
+    private final ShortcutService mService;
+    private final Object mLock;
+
+    /**
+     * Internal for {@link android.content.pm.LauncherApps.PinItemRequest} which receives callbacks.
+     */
+    private static class PinShortcutRequestInner extends IPinItemRequest.Stub {
+        private final ShortcutRequestPinProcessor mProcessor;
+        /** Original shortcut passed by the app. */
+        public final ShortcutInfo shortcutOriginal;
+
+        /**
+         * Cloned shortcut that's passed to the launcher.  The notable difference from
+         * {@link #shortcutOriginal} is it must not have the intent.
+         */
+        public final ShortcutInfo shortcutForLauncher;
+
+        private final IntentSender mResultIntent;
+
+        public final String launcherPackage;
+        public final int launcherUserId;
+        public final boolean preExisting;
+
+        @GuardedBy("this")
+        private boolean mAccepted;
+
+        private PinShortcutRequestInner(ShortcutRequestPinProcessor processor,
+                ShortcutInfo shortcutOriginal, ShortcutInfo shortcutForLauncher,
+                IntentSender resultIntent,
+                String launcherPackage, int launcherUserId, boolean preExisting) {
+            mProcessor = processor;
+            this.shortcutOriginal = shortcutOriginal;
+            this.shortcutForLauncher = shortcutForLauncher;
+            mResultIntent = resultIntent;
+            this.launcherPackage = launcherPackage;
+            this.launcherUserId = launcherUserId;
+            this.preExisting = preExisting;
+        }
+
+        @Override
+        public boolean isValid() {
+            // TODO When an app calls requestPinShortcut(), all pending requests should be
+            // invalidated.
+            synchronized (this) {
+                return !mAccepted;
+            }
+        }
+
+        /**
+         * Called when the launcher calls {@link PinItemRequest#accept}.
+         */
+        @Override
+        public boolean accept(Bundle options) {
+            // Make sure the options are unparcellable by the FW. (e.g. not containing unknown
+            // classes.)
+            if (options != null) {
+                try {
+                    options.size();
+                } catch (RuntimeException e) {
+                    throw new IllegalArgumentException("options cannot be unparceled", e);
+                }
+            }
+            synchronized (this) {
+                if (mAccepted) {
+                    throw new IllegalStateException("accept() called already");
+                }
+                mAccepted = true;
+            }
+            if (DEBUG) {
+                Slog.d(TAG, "Launcher accepted shortcut. ID=" + shortcutOriginal.getId()
+                        + " package=" + shortcutOriginal.getPackage()
+                        + " options=" + options);
+            }
+
+            // Pin it and send the result intent.
+            if (mProcessor.directPinShortcut(this)) {
+                mProcessor.sendResultIntent(mResultIntent);
+                return true;
+            } else {
+                return false;
+            }
+        }
+    }
+
+    public ShortcutRequestPinProcessor(ShortcutService service, Object lock) {
+        mService = service;
+        mLock = lock;
+    }
+
+    public boolean isRequestPinnedShortcutSupported(int callingUserId) {
+        return getRequestPinShortcutConfirmationActivity(callingUserId) != null;
+    }
+
+    /**
+     * Handle {@link android.content.pm.ShortcutManager#requestPinShortcut)}.
+     */
+    public boolean requestPinShortcutLocked(ShortcutInfo inShortcut, IntentSender resultIntent) {
+
+        // First, make sure the launcher supports it.
+
+        // Find the confirmation activity in the default launcher.
+        final Pair<ComponentName, Integer> confirmActivity =
+                getRequestPinShortcutConfirmationActivity(inShortcut.getUserId());
+
+        // If the launcher doesn't support it, just return a rejected result and finish.
+        if (confirmActivity == null) {
+            Log.w(TAG, "Launcher doesn't support requestPinnedShortcut(). Shortcut not created.");
+            return false;
+        }
+
+        final ComponentName launcherComponent = confirmActivity.first;
+        final String launcherPackage = confirmActivity.first.getPackageName();
+        final int launcherUserId = confirmActivity.second;
+
+        // Make sure the launcher user is unlocked. (it's always the parent profile, so should
+        // really be unlocked here though.)
+        mService.throwIfUserLockedL(launcherUserId);
+
+        // Next, validate the incoming shortcut, etc.
+
+        final ShortcutPackage ps = mService.getPackageShortcutsForPublisherLocked(
+                inShortcut.getPackage(), inShortcut.getUserId());
+
+        final ShortcutInfo existing = ps.findShortcutById(inShortcut.getId());
+        final boolean existsAlready = existing != null;
+
+        if (DEBUG) {
+            Slog.d(TAG, "requestPinnedShortcut package=" + inShortcut.getPackage()
+                    + " existsAlready=" + existsAlready
+                    + " shortcut=" + inShortcut.toInsecureString());
+        }
+
+        // This is the shortcut that'll be sent to the launcher.
+        final ShortcutInfo shortcutForLauncher;
+
+        if (existsAlready) {
+            validateExistingShortcut(existing);
+
+            // See if it's already pinned.
+            if (mService.getLauncherShortcutsLocked(
+                    launcherPackage, existing.getUserId(), launcherUserId).hasPinned(existing)) {
+                Log.i(TAG, "Launcher's already pinning shortcut " + existing.getId()
+                        + " for package " + existing.getPackage());
+                sendResultIntent(resultIntent);
+                return true;
+            }
+
+            // Pass a clone, not the original.
+            // Note this will remove the intent and icons.
+            shortcutForLauncher = existing.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
+
+            // FLAG_PINNED is still set, if it's pinned by other launchers.
+            shortcutForLauncher.clearFlags(ShortcutInfo.FLAG_PINNED);
+        } else {
+            // It doesn't exist, so it must have all mandatory fields.
+            mService.validateShortcutForPinRequest(inShortcut);
+
+            // Initialize the ShortcutInfo for pending approval.
+            inShortcut.resolveResourceStrings(mService.injectGetResourcesForApplicationAsUser(
+                    inShortcut.getPackage(), inShortcut.getUserId()));
+            if (DEBUG) {
+                Slog.d(TAG, "resolved shortcut=" + inShortcut.toInsecureString());
+            }
+            // We should strip out the intent, but should preserve the icon.
+            shortcutForLauncher = inShortcut.clone(
+                    ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER_APPROVAL);
+        }
+
+        // Create a request object.
+        final PinShortcutRequestInner inner =
+                new PinShortcutRequestInner(this, inShortcut, shortcutForLauncher, resultIntent,
+                        launcherPackage, launcherUserId, existsAlready);
+
+        final PinItemRequest outer = new PinItemRequest(PinItemRequest.REQUEST_TYPE_SHORTCUT,
+                shortcutForLauncher, inner);
+
+        return startRequestConfirmActivity(launcherComponent, launcherUserId, outer);
+    }
+
+    private void validateExistingShortcut(ShortcutInfo shortcutInfo) {
+        // Make sure it's enabled.
+        // (Because we can't always force enable it automatically as it may be a stale
+        // manifest shortcut.)
+        Preconditions.checkArgument(shortcutInfo.isEnabled(),
+                "Shortcut ID=" + shortcutInfo + " already exists but disabled.");
+
+    }
+
+    private boolean startRequestConfirmActivity(ComponentName activity, int launcherUserId,
+            PinItemRequest request) {
+        // Start the activity.
+        final Intent confirmIntent = new Intent(LauncherApps.ACTION_CONFIRM_PIN_ITEM);
+        confirmIntent.setComponent(activity);
+        confirmIntent.putExtra(LauncherApps.EXTRA_PIN_ITEM_REQUEST, request);
+        confirmIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+
+        final long token = mService.injectClearCallingIdentity();
+        try {
+            mService.mContext.startActivityAsUser(
+                    confirmIntent, UserHandle.of(launcherUserId));
+        } catch (RuntimeException e) { // ActivityNotFoundException, etc.
+            Log.e(TAG, "Unable to start activity " + activity, e);
+            return false;
+        } finally {
+            mService.injectRestoreCallingIdentity(token);
+        }
+        return true;
+    }
+
+    /**
+     * Find the activity that handles {@link LauncherApps#ACTION_CONFIRM_PIN_ITEM} in the
+     * default launcher.
+     */
+    @Nullable
+    @VisibleForTesting
+    Pair<ComponentName, Integer> getRequestPinShortcutConfirmationActivity(
+            int callingUserId) {
+        // Find the default launcher.
+        final int launcherUserId = mService.getParentOrSelfUserId(callingUserId);
+        final ComponentName defaultLauncher = mService.getDefaultLauncher(launcherUserId);
+
+        if (defaultLauncher == null) {
+            Log.e(TAG, "Default launcher not found.");
+            return null;
+        }
+        final ComponentName activity = mService.injectGetPinConfirmationActivity(
+                defaultLauncher.getPackageName(), launcherUserId);
+        return (activity == null) ? null : Pair.create(activity, launcherUserId);
+    }
+
+    public void sendResultIntent(@Nullable IntentSender intent) {
+        if (DEBUG) {
+            Slog.d(TAG, "Sending result intent.");
+        }
+        mService.injectSendIntentSender(intent);
+    }
+
+    /**
+     * The last step of the "request pin shortcut" flow.  Called when the launcher accepted a
+     * request.
+     */
+    public boolean directPinShortcut(PinShortcutRequestInner request) {
+
+        final ShortcutInfo original = request.shortcutOriginal;
+        final int appUserId = original.getUserId();
+        final String appPackageName = original.getPackage();
+        final int launcherUserId = request.launcherUserId;
+        final String launcherPackage = request.launcherPackage;
+        final String shortcutId = original.getId();
+
+        synchronized (mLock) {
+            if (!(mService.isUserUnlockedL(appUserId)
+                    && mService.isUserUnlockedL(request.launcherUserId))) {
+                Log.w(TAG, "User is locked now.");
+                return false;
+            }
+
+            final ShortcutPackage ps = mService.getPackageShortcutsForPublisherLocked(
+                    appPackageName, appUserId);
+            final ShortcutInfo current = ps.findShortcutById(shortcutId);
+
+            // The shortcut might have been changed, so we need to do the same validation again.
+            try {
+                if (current == null) {
+                    // It doesn't exist, so it must have all necessary fields.
+                    mService.validateShortcutForPinRequest(original);
+                } else {
+                    validateExistingShortcut(current);
+                }
+            } catch (RuntimeException e) {
+                Log.w(TAG, "Unable to pin shortcut: " + e.getMessage());
+                return false;
+            }
+
+            // If the shortcut doesn't exist, need to create it.
+            // First, create it as a dynamic shortcut.
+            if (current == null) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Temporarily adding " + shortcutId + " as dynamic");
+                }
+                // Add as a dynamic shortcut.
+                if (original.getActivity() == null) {
+                    original.setActivity(mService.getDummyMainActivity(appPackageName));
+                }
+                ps.addOrUpdateDynamicShortcut(original);
+            }
+
+            // Pin the shortcut.
+            if (DEBUG) {
+                Slog.d(TAG, "Pinning " + shortcutId);
+            }
+
+            final ShortcutLauncher launcher = mService.getLauncherShortcutsLocked(
+                    launcherPackage, appUserId, launcherUserId);
+            launcher.attemptToRestoreIfNeededAndSave();
+            launcher.addPinnedShortcut(appPackageName, appUserId, shortcutId);
+
+            if (current == null) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Removing " + shortcutId + " as dynamic");
+                }
+                ps.deleteDynamicWithId(shortcutId);
+            }
+
+            ps.adjustRanks(); // Shouldn't be needed, but just in case.
+        }
+
+        mService.verifyStates();
+        mService.packageShortcutsChanged(appPackageName, appUserId);
+
+        return true;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index c5c1c0c..436a53c 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -29,6 +29,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.content.IntentSender.SendIntentException;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
@@ -42,8 +44,10 @@
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
 import android.content.pm.ShortcutServiceInternal;
 import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener;
+import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.graphics.Bitmap;
@@ -190,6 +194,8 @@
     private static final String KEY_LOW_RAM = "lowRam";
     private static final String KEY_ICON_SIZE = "iconSize";
 
+    private static final String DUMMY_MAIN_ACTIVITY = "android.__dummy__";
+
     @VisibleForTesting
     interface ConfigConstants {
         /**
@@ -298,6 +304,8 @@
     private final UsageStatsManagerInternal mUsageStatsManagerInternal;
     private final ActivityManagerInternal mActivityManagerInternal;
 
+    private final ShortcutRequestPinProcessor mShortcutRequestPinProcessor;
+
     @GuardedBy("mLock")
     final SparseIntArray mUidState = new SparseIntArray();
 
@@ -336,8 +344,9 @@
         int IS_ACTIVITY_ENABLED = 13;
         int PACKAGE_UPDATE_CHECK = 14;
         int ASYNC_PRELOAD_USER_DELAY = 15;
+        int GET_DEFAULT_LAUNCHER = 16;
 
-        int COUNT = ASYNC_PRELOAD_USER_DELAY + 1;
+        int COUNT = GET_DEFAULT_LAUNCHER + 1;
     }
 
     private static final String[] STAT_LABELS = {
@@ -356,7 +365,8 @@
             "checkLauncherActivity",
             "isActivityEnabled",
             "packageUpdateCheck",
-            "asyncPreloadUserDelay"
+            "asyncPreloadUserDelay",
+            "getDefaultLauncher()"
     };
 
     final Object mStatLock = new Object();
@@ -417,6 +427,8 @@
         mActivityManagerInternal = Preconditions.checkNotNull(
                 LocalServices.getService(ActivityManagerInternal.class));
 
+        mShortcutRequestPinProcessor = new ShortcutRequestPinProcessor(this, mLock);
+
         if (onlyForPackageManagerApis) {
             return; // Don't do anything further.  For unit tests only.
         }
@@ -1591,12 +1603,11 @@
      * - Make sure the intent's extras are persistable, and them to set
      * {@link ShortcutInfo#mIntentPersistableExtrases}.  Also clear its extras.
      * - Clear flags.
-     *
-     * TODO Detailed unit tests
      */
-    private void fixUpIncomingShortcutInfo(@NonNull ShortcutInfo shortcut, boolean forUpdate) {
+    private void fixUpIncomingShortcutInfo(@NonNull ShortcutInfo shortcut, boolean forUpdate,
+            boolean forPinRequest) {
         Preconditions.checkNotNull(shortcut, "Null shortcut detected");
-        if (shortcut.getActivity() != null) {
+        if (!forPinRequest && shortcut.getActivity() != null) {
             Preconditions.checkState(
                     shortcut.getPackage().equals(shortcut.getActivity().getPackageName()),
                     "Cannot publish shortcut: activity " + shortcut.getActivity() + " does not"
@@ -1608,10 +1619,13 @@
         }
 
         if (!forUpdate) {
-            shortcut.enforceMandatoryFields(/* forPinned= */ false);
-            Preconditions.checkArgument(
-                    injectIsMainActivity(shortcut.getActivity(), shortcut.getUserId()),
-                    "Cannot publish shortcut: " + shortcut.getActivity() + " is not main activity");
+            shortcut.enforceMandatoryFields(/* forPinned= */ forPinRequest);
+            if (!forPinRequest) {
+                Preconditions.checkArgument(
+                        injectIsMainActivity(shortcut.getActivity(), shortcut.getUserId()),
+                        "Cannot publish shortcut: " + shortcut.getActivity()
+                                + " is not main activity");
+            }
         }
         if (shortcut.getIcon() != null) {
             ShortcutInfo.validateIcon(shortcut.getIcon());
@@ -1620,11 +1634,18 @@
         shortcut.replaceFlags(0);
     }
 
+    private void fixUpIncomingShortcutInfo(@NonNull ShortcutInfo shortcut, boolean forUpdate) {
+        fixUpIncomingShortcutInfo(shortcut, forUpdate, /*forPinRequest=*/ false);
+    }
+
+    public void validateShortcutForPinRequest(@NonNull ShortcutInfo shortcut) {
+        fixUpIncomingShortcutInfo(shortcut, /* forUpdate= */ false, /*forPinRequest=*/ true);
+    }
+
     /**
      * When a shortcut has no target activity, set the default one from the package.
      */
     private void fillInDefaultActivity(List<ShortcutInfo> shortcuts) {
-
         ComponentName defaultActivity = null;
         for (int i = shortcuts.size() - 1; i >= 0; i--) {
             final ShortcutInfo si = shortcuts.get(i);
@@ -1834,6 +1855,31 @@
     }
 
     @Override
+    public boolean requestPinShortcut(String packageName, ShortcutInfo shortcut,
+            IntentSender resultIntent, int userId) {
+        verifyCaller(packageName, userId);
+        Preconditions.checkNotNull(shortcut);
+        Preconditions.checkArgument(shortcut.isEnabled(), "Shortcut must be enabled");
+
+        final boolean ret;
+        synchronized (mLock) {
+            throwIfUserLockedL(userId);
+
+            Preconditions.checkState(isUidForegroundLocked(injectBinderCallingUid()),
+                    "Calling application must have a foreground activity or a foreground service");
+
+            // TODO Cancel all pending requests from the caller.
+
+            // Send request to the launcher, if supported.
+            ret = mShortcutRequestPinProcessor.requestPinShortcutLocked(shortcut, resultIntent);
+        }
+
+        verifyStates();
+
+        return ret;
+    }
+
+    @Override
     public void disableShortcuts(String packageName, List shortcutIds,
             CharSequence disabledMessage, int disabledMessageResId, @UserIdInt int userId) {
         verifyCaller(packageName, userId);
@@ -2049,6 +2095,16 @@
         }
     }
 
+    @Override
+    public boolean isRequestPinShortcutSupported(int callingUserId) {
+        final long token = injectClearCallingIdentity();
+        try {
+            return mShortcutRequestPinProcessor.isRequestPinnedShortcutSupported(callingUserId);
+        } finally {
+            injectRestoreCallingIdentity(token);
+        }
+    }
+
     /**
      * Reset all throttling, for developer options and command line.  Only system/shell can call
      * it.
@@ -2113,77 +2169,22 @@
     // This method is extracted so we can directly call this method from unit tests,
     // even when hasShortcutPermission() is overridden.
     @VisibleForTesting
-    boolean hasShortcutHostPermissionInner(@NonNull String callingPackage, int userId) {
+    boolean hasShortcutHostPermissionInner(@NonNull String packageName, int userId) {
         synchronized (mLock) {
             throwIfUserLockedL(userId);
 
             final ShortcutUser user = getUserShortcutsLocked(userId);
 
-            // Always trust the in-memory cache.
+            // Always trust the cached component.
             final ComponentName cached = user.getCachedLauncher();
             if (cached != null) {
-                if (cached.getPackageName().equals(callingPackage)) {
+                if (cached.getPackageName().equals(packageName)) {
                     return true;
                 }
             }
             // If the cached one doesn't match, then go ahead
 
-            final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
-
-            // Default launcher from package manager.
-            final long startGetHomeActivitiesAsUser = injectElapsedRealtime();
-            final ComponentName defaultLauncher = mPackageManagerInternal
-                    .getHomeActivitiesAsUser(allHomeCandidates, userId);
-            logDurationStat(Stats.GET_DEFAULT_HOME, startGetHomeActivitiesAsUser);
-
-            ComponentName detected;
-            if (defaultLauncher != null) {
-                detected = defaultLauncher;
-                if (DEBUG) {
-                    Slog.v(TAG, "Default launcher from PM: " + detected);
-                }
-            } else {
-                detected = user.getLastKnownLauncher();
-
-                if (detected != null) {
-                    if (injectIsActivityEnabledAndExported(detected, userId)) {
-                        if (DEBUG) {
-                            Slog.v(TAG, "Cached launcher: " + detected);
-                        }
-                    } else {
-                        Slog.w(TAG, "Cached launcher " + detected + " no longer exists");
-                        detected = null;
-                        user.clearLauncher();
-                    }
-                }
-            }
-
-            if (detected == null) {
-                // If we reach here, that means it's the first check since the user was created,
-                // and there's already multiple launchers and there's no default set.
-                // Find the system one with the highest priority.
-                // (We need to check the priority too because of FallbackHome in Settings.)
-                // If there's no system launcher yet, then no one can access shortcuts, until
-                // the user explicitly
-                final int size = allHomeCandidates.size();
-
-                int lastPriority = Integer.MIN_VALUE;
-                for (int i = 0; i < size; i++) {
-                    final ResolveInfo ri = allHomeCandidates.get(i);
-                    if (!ri.activityInfo.applicationInfo.isSystemApp()) {
-                        continue;
-                    }
-                    if (DEBUG) {
-                        Slog.d(TAG, String.format("hasShortcutPermissionInner: pkg=%s prio=%d",
-                                ri.activityInfo.getComponentName(), ri.priority));
-                    }
-                    if (ri.priority < lastPriority) {
-                        continue;
-                    }
-                    detected = ri.activityInfo.getComponentName();
-                    lastPriority = ri.priority;
-                }
-            }
+            final ComponentName detected = getDefaultLauncher(userId);
 
             // Update the cache.
             user.setLauncher(detected);
@@ -2191,7 +2192,7 @@
                 if (DEBUG) {
                     Slog.v(TAG, "Detected launcher: " + detected);
                 }
-                return detected.getPackageName().equals(callingPackage);
+                return detected.getPackageName().equals(packageName);
             } else {
                 // Default launcher not found.
                 return false;
@@ -2199,6 +2200,80 @@
         }
     }
 
+    @Nullable
+    ComponentName getDefaultLauncher(@UserIdInt int userId) {
+        final long start = injectElapsedRealtime();
+        final long token = injectClearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                throwIfUserLockedL(userId);
+
+                final ShortcutUser user = getUserShortcutsLocked(userId);
+
+                final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
+
+                // Default launcher from package manager.
+                final long startGetHomeActivitiesAsUser = injectElapsedRealtime();
+                final ComponentName defaultLauncher = mPackageManagerInternal
+                        .getHomeActivitiesAsUser(allHomeCandidates, userId);
+                logDurationStat(Stats.GET_DEFAULT_HOME, startGetHomeActivitiesAsUser);
+
+                ComponentName detected = null;
+                if (defaultLauncher != null) {
+                    detected = defaultLauncher;
+                    if (DEBUG) {
+                        Slog.v(TAG, "Default launcher from PM: " + detected);
+                    }
+                } else {
+                    detected = user.getLastKnownLauncher();
+
+                    if (detected != null) {
+                        if (injectIsActivityEnabledAndExported(detected, userId)) {
+                            if (DEBUG) {
+                                Slog.v(TAG, "Cached launcher: " + detected);
+                            }
+                        } else {
+                            Slog.w(TAG, "Cached launcher " + detected + " no longer exists");
+                            detected = null;
+                            user.clearLauncher();
+                        }
+                    }
+                }
+
+                if (detected == null) {
+                    // If we reach here, that means it's the first check since the user was created,
+                    // and there's already multiple launchers and there's no default set.
+                    // Find the system one with the highest priority.
+                    // (We need to check the priority too because of FallbackHome in Settings.)
+                    // If there's no system launcher yet, then no one can access shortcuts, until
+                    // the user explicitly
+                    final int size = allHomeCandidates.size();
+
+                    int lastPriority = Integer.MIN_VALUE;
+                    for (int i = 0; i < size; i++) {
+                        final ResolveInfo ri = allHomeCandidates.get(i);
+                        if (!ri.activityInfo.applicationInfo.isSystemApp()) {
+                            continue;
+                        }
+                        if (DEBUG) {
+                            Slog.d(TAG, String.format("hasShortcutPermissionInner: pkg=%s prio=%d",
+                                    ri.activityInfo.getComponentName(), ri.priority));
+                        }
+                        if (ri.priority < lastPriority) {
+                            continue;
+                        }
+                        detected = ri.activityInfo.getComponentName();
+                        lastPriority = ri.priority;
+                    }
+                }
+                return detected;
+            }
+        } finally {
+            injectRestoreCallingIdentity(token);
+            logDurationStat(Stats.GET_DEFAULT_LAUNCHER, start);
+        }
+    }
+
     // === House keeping ===
 
     private void cleanUpPackageForAllLoadedUsers(String packageName, @UserIdInt int packageUserId,
@@ -3034,10 +3109,21 @@
         if (activity != null) {
             baseIntent.setComponent(activity);
         }
+        return queryActivities(baseIntent, userId, /* exportedOnly =*/ true);
+    }
 
-        final List<ResolveInfo> resolved =
-                mContext.getPackageManager().queryIntentActivitiesAsUser(
-                        baseIntent, PACKAGE_MATCH_FLAGS, userId);
+    @NonNull
+    List<ResolveInfo> queryActivities(@NonNull Intent intent, int userId,
+            boolean exportedOnly) {
+        final List<ResolveInfo> resolved;
+        final long token = injectClearCallingIdentity();
+        try {
+            resolved =
+                    mContext.getPackageManager().queryIntentActivitiesAsUser(
+                            intent, PACKAGE_MATCH_FLAGS, userId);
+        } finally {
+            injectRestoreCallingIdentity(token);
+        }
         if (resolved == null || resolved.size() == 0) {
             return EMPTY_RESOLVE_INFO;
         }
@@ -3045,7 +3131,9 @@
         if (!isInstalled(resolved.get(0).activityInfo)) {
             return EMPTY_RESOLVE_INFO;
         }
-        resolved.removeIf(ACTIVITY_NOT_EXPORTED);
+        if (exportedOnly) {
+            resolved.removeIf(ACTIVITY_NOT_EXPORTED);
+        }
         return resolved;
     }
 
@@ -3056,14 +3144,11 @@
     @Nullable
     ComponentName injectGetDefaultMainActivity(@NonNull String packageName, int userId) {
         final long start = injectElapsedRealtime();
-        final long token = injectClearCallingIdentity();
         try {
             final List<ResolveInfo> resolved =
                     queryActivities(getMainActivityIntent(), packageName, null, userId);
             return resolved.size() == 0 ? null : resolved.get(0).activityInfo.getComponentName();
         } finally {
-            injectRestoreCallingIdentity(token);
-
             logDurationStat(Stats.GET_LAUNCHER_ACTIVITY, start);
         }
     }
@@ -3073,31 +3158,36 @@
      */
     boolean injectIsMainActivity(@NonNull ComponentName activity, int userId) {
         final long start = injectElapsedRealtime();
-        final long token = injectClearCallingIdentity();
         try {
-            final List<ResolveInfo> resolved =
-                    queryActivities(getMainActivityIntent(), activity.getPackageName(),
-                            activity, userId);
+            if (DUMMY_MAIN_ACTIVITY.equals(activity.getClassName())) {
+                return true;
+            }
+            final List<ResolveInfo> resolved = queryActivities(
+                    getMainActivityIntent(), activity.getPackageName(), activity, userId);
             return resolved.size() > 0;
         } finally {
-            injectRestoreCallingIdentity(token);
-
             logDurationStat(Stats.CHECK_LAUNCHER_ACTIVITY, start);
         }
     }
 
     /**
+     * Create a dummy "main activity" component name which is used to create a dynamic shortcut
+     * with no main activity temporarily.
+     */
+    @NonNull
+    ComponentName getDummyMainActivity(@NonNull String packageName) {
+        return new ComponentName(packageName, DUMMY_MAIN_ACTIVITY);
+    }
+
+    /**
      * Return all the enabled, exported and main activities from a package.
      */
     @NonNull
     List<ResolveInfo> injectGetMainActivities(@NonNull String packageName, int userId) {
         final long start = injectElapsedRealtime();
-        final long token = injectClearCallingIdentity();
         try {
             return queryActivities(getMainActivityIntent(), packageName, null, userId);
         } finally {
-            injectRestoreCallingIdentity(token);
-
             logDurationStat(Stats.CHECK_LAUNCHER_ACTIVITY, start);
         }
     }
@@ -3109,17 +3199,33 @@
     boolean injectIsActivityEnabledAndExported(
             @NonNull ComponentName activity, @UserIdInt int userId) {
         final long start = injectElapsedRealtime();
-        final long token = injectClearCallingIdentity();
         try {
             return queryActivities(new Intent(), activity.getPackageName(), activity, userId)
                     .size() > 0;
         } finally {
-            injectRestoreCallingIdentity(token);
-
             logDurationStat(Stats.IS_ACTIVITY_ENABLED, start);
         }
     }
 
+    /**
+     * Get the {@link LauncherApps#ACTION_CONFIRM_PIN_ITEM} activity in a given package.
+     */
+    @Nullable
+    ComponentName injectGetPinConfirmationActivity(@NonNull String launcherPackageName,
+            int launcherUserId) {
+        Preconditions.checkNotNull(launcherPackageName);
+
+        final Intent confirmIntent = new Intent(LauncherApps.ACTION_CONFIRM_PIN_ITEM);
+        confirmIntent.setPackage(launcherPackageName);
+
+        final List<ResolveInfo> candidates = queryActivities(
+                confirmIntent, launcherUserId, /* exportedOnly =*/ false);
+        for (ResolveInfo ri : candidates) {
+            return ri.activityInfo.getComponentName();
+        }
+        return null;
+    }
+
     boolean injectIsSafeModeEnabled() {
         final long token = injectClearCallingIdentity();
         try {
@@ -3133,6 +3239,32 @@
         }
     }
 
+    /**
+     * If {@code userId} is of a managed profile, return the parent user ID.  Otherwise return
+     * itself.
+     */
+    int getParentOrSelfUserId(int userId) {
+        final long token = injectClearCallingIdentity();
+        try {
+            final UserInfo parent = mUserManager.getProfileParent(userId);
+            return (parent != null) ? parent.id : userId;
+        } finally {
+            injectRestoreCallingIdentity(token);
+        }
+    }
+
+    void injectSendIntentSender(IntentSender intentSender) {
+        if (intentSender == null) {
+            return;
+        }
+        try {
+            intentSender.sendIntent(mContext, /* code= */ 0, /* intent= */ null,
+                    /* onFinished=*/ null, /* handler= */ null);
+        } catch (SendIntentException e) {
+            Slog.w(TAG, "sendIntent failed().", e);
+        }
+    }
+
     // === Backup & restore ===
 
     boolean shouldBackupApp(String packageName, int userId) {
@@ -3749,6 +3881,11 @@
         }
     }
 
+    @VisibleForTesting
+    ShortcutRequestPinProcessor getShortcutRequestPinProcessorForTest() {
+        return mShortcutRequestPinProcessor;
+    }
+
     /**
      * Control whether {@link #verifyStates} should be performed.  We always perform it during unit
      * tests.
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index bac7a76..05228ec 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2269,8 +2269,11 @@
 
     private UserInfo createUserInternal(String name, int flags, int parentId,
             String[] disallowedPackages) {
-        if (hasUserRestriction(UserManager.DISALLOW_ADD_USER, UserHandle.getCallingUserId())) {
-            Log.w(LOG_TAG, "Cannot add user. DISALLOW_ADD_USER is enabled.");
+        String restriction = ((flags & UserInfo.FLAG_MANAGED_PROFILE) != 0)
+                ? UserManager.DISALLOW_ADD_MANAGED_PROFILE
+                : UserManager.DISALLOW_ADD_USER;
+        if (hasUserRestriction(restriction, UserHandle.getCallingUserId())) {
+            Log.w(LOG_TAG, "Cannot add user. " + restriction + " is enabled.");
             return null;
         }
         return createUserInternalUnchecked(name, flags, parentId, disallowedPackages);
@@ -2541,9 +2544,16 @@
     public boolean removeUser(int userHandle) {
         Slog.i(LOG_TAG, "removeUser u" + userHandle);
         checkManageOrCreateUsersPermission("Only the system can remove users");
-        if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(
-                UserManager.DISALLOW_REMOVE_USER, false)) {
-            Log.w(LOG_TAG, "Cannot remove user. DISALLOW_REMOVE_USER is enabled.");
+
+        final boolean isManagedProfile;
+        synchronized (mUsersLock) {
+            UserInfo userInfo = getUserInfoLU(userHandle);
+            isManagedProfile = userInfo != null && userInfo.isManagedProfile();
+        }
+        String restriction = isManagedProfile
+                ? UserManager.DISALLOW_REMOVE_MANAGED_PROFILE : UserManager.DISALLOW_REMOVE_USER;
+        if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(restriction, false)) {
+            Log.w(LOG_TAG, "Cannot remove user. " + restriction + " is enabled.");
             return false;
         }
         return removeUserUnchecked(userHandle);
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 7ec3c19..e91cce1 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -75,12 +75,14 @@
             UserManager.DISALLOW_USB_FILE_TRANSFER,
             UserManager.DISALLOW_CONFIG_CREDENTIALS,
             UserManager.DISALLOW_REMOVE_USER,
+            UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
             UserManager.DISALLOW_DEBUGGING_FEATURES,
             UserManager.DISALLOW_CONFIG_VPN,
             UserManager.DISALLOW_CONFIG_TETHERING,
             UserManager.DISALLOW_NETWORK_RESET,
             UserManager.DISALLOW_FACTORY_RESET,
             UserManager.DISALLOW_ADD_USER,
+            UserManager.DISALLOW_ADD_MANAGED_PROFILE,
             UserManager.ENSURE_VERIFY_APPS,
             UserManager.DISALLOW_CONFIG_CELL_BROADCASTS,
             UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
@@ -124,6 +126,8 @@
             UserManager.DISALLOW_NETWORK_RESET,
             UserManager.DISALLOW_FACTORY_RESET,
             UserManager.DISALLOW_ADD_USER,
+            UserManager.DISALLOW_ADD_MANAGED_PROFILE,
+            UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
             UserManager.DISALLOW_CONFIG_CELL_BROADCASTS,
             UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
             UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
@@ -155,6 +159,13 @@
     );
 
     /**
+     * User restrictions that default to {@code true} for device owners.
+     */
+    private static final Set<String> DEFAULT_ENABLED_FOR_DEVICE_OWNERS = Sets.newArraySet(
+            UserManager.DISALLOW_ADD_MANAGED_PROFILE
+    );
+
+    /**
      * Throws {@link IllegalArgumentException} if the given restriction name is invalid.
      */
     public static boolean isValidRestriction(@NonNull String restriction) {
@@ -249,6 +260,13 @@
     }
 
     /**
+     * Returns the user restrictions that default to {@code true} for device owners.
+     */
+    public static @NonNull Set<String> getDefaultEnabledForDeviceOwner() {
+        return DEFAULT_ENABLED_FOR_DEVICE_OWNERS;
+    }
+
+    /**
      * Takes restrictions that can be set by device owner, and sort them into what should be applied
      * globally and what should be applied only on the current user.
      */
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index afad328..9d4b51f 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -229,6 +229,7 @@
 import com.android.server.policy.keyguard.KeyguardStateMonitor.StateCallback;
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.wm.AppTransition;
+import com.android.server.vr.VrManagerInternal;
 
 import java.io.File;
 import java.io.FileReader;
@@ -6455,6 +6456,7 @@
                 mKeyguardDelegate.onScreenTurnedOff();
             }
         }
+        reportScreenStateToVrManager(false);
     }
 
     // Called on the DisplayManager's DisplayPowerController thread.
@@ -6490,6 +6492,15 @@
                 mKeyguardDelegate.onScreenTurnedOn();
             }
         }
+        reportScreenStateToVrManager(true);
+    }
+
+    private void reportScreenStateToVrManager(boolean isScreenOn) {
+        VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
+        if (vrService == null) {
+            return;
+        }
+        vrService.onScreenStateChanged(isScreenOn);
     }
 
     private void finishWindowsDrawn() {
@@ -6674,9 +6685,7 @@
 
         // Navigation bar and status bar.
         getNonDecorInsetsLw(displayRotation, displayWidth, displayHeight, outInsets);
-        if (mStatusBar != null) {
-            outInsets.top = mStatusBarHeight;
-        }
+        outInsets.top = mStatusBarHeight;
     }
 
     @Override
@@ -6685,7 +6694,7 @@
         outInsets.setEmpty();
 
         // Only navigation bar
-        if (mNavigationBar != null) {
+        if (mHasNavigationBar) {
             int position = navigationBarPosition(displayWidth, displayHeight, displayRotation);
             if (position == NAV_BAR_BOTTOM) {
                 outInsets.bottom = getNavigationBarHeight(displayRotation, mUiMode);
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 1790554..f2ccac5 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -134,6 +134,8 @@
     private static final int DIRTY_DOCK_STATE = 1 << 10;
     // Dirty bit: brightness boost changed
     private static final int DIRTY_SCREEN_BRIGHTNESS_BOOST = 1 << 11;
+    // Dirty bit: sQuiescent changed
+    private static final int DIRTY_QUIESCENT = 1 << 12;
 
     // Summarizes the state of all active wakelocks.
     private static final int WAKE_LOCK_CPU = 1 << 0;
@@ -169,6 +171,9 @@
     // Default setting for double tap to wake.
     private static final int DEFAULT_DOUBLE_TAP_TO_WAKE = 0;
 
+    // System property indicating that the screen should remain off until an explicit user action
+    private static final String SYSTEM_PROPERTY_QUIESCENT = "ro.boot.quiescent";
+
     /** Constants for {@link #shutdownOrRebootInternal} */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({HALT_MODE_SHUTDOWN, HALT_MODE_REBOOT, HALT_MODE_REBOOT_SAFE_MODE})
@@ -398,6 +403,9 @@
     // True if the device should stay on.
     private boolean mStayOn;
 
+    // True if the lights should stay off until an explicit user action.
+    private static boolean sQuiescent;
+
     // True if the proximity sensor reads a positive result.
     private boolean mProximityPositive;
 
@@ -530,6 +538,8 @@
 
             mWakefulness = WAKEFULNESS_AWAKE;
 
+            sQuiescent = SystemProperties.get(SYSTEM_PROPERTY_QUIESCENT, "0").equals("1");
+
             nativeInit();
             nativeSetAutoSuspend(false);
             nativeSetInteractive(true);
@@ -1190,12 +1200,19 @@
                         && eventTime > mLastUserActivityTime) {
                     mLastUserActivityTimeNoChangeLights = eventTime;
                     mDirty |= DIRTY_USER_ACTIVITY;
+                    if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {
+                        mDirty |= DIRTY_QUIESCENT;
+                    }
+
                     return true;
                 }
             } else {
                 if (eventTime > mLastUserActivityTime) {
                     mLastUserActivityTime = eventTime;
                     mDirty |= DIRTY_USER_ACTIVITY;
+                    if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {
+                        mDirty |= DIRTY_QUIESCENT;
+                    }
                     return true;
                 }
             }
@@ -2096,7 +2113,7 @@
         final boolean oldDisplayReady = mDisplayReady;
         if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
                 | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
-                | DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST)) != 0) {
+                | DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST | DIRTY_QUIESCENT)) != 0) {
             mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked();
 
             // Determine appropriate screen brightness and auto-brightness adjustments.
@@ -2163,6 +2180,9 @@
                     mRequestWaitForNegativeProximity);
             mRequestWaitForNegativeProximity = false;
 
+            if ((dirty & DIRTY_QUIESCENT) != 0) {
+                sQuiescent = false;
+            }
             if (DEBUG_SPEW) {
                 Slog.d(TAG, "updateDisplayPowerStateLocked: mDisplayReady=" + mDisplayReady
                         + ", policy=" + mDisplayPowerRequest.policy
@@ -2170,8 +2190,8 @@
                         + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)
                         + ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
                         + ", mBootCompleted=" + mBootCompleted
-                        + ", mScreenBrightnessBoostInProgress="
-                                + mScreenBrightnessBoostInProgress);
+                        + ", mScreenBrightnessBoostInProgress=" + mScreenBrightnessBoostInProgress
+                        + ", sQuiescent=" + sQuiescent);
             }
         }
         return mDisplayReady && !oldDisplayReady;
@@ -2210,7 +2230,7 @@
     }
 
     private int getDesiredScreenPolicyLocked() {
-        if (mWakefulness == WAKEFULNESS_ASLEEP) {
+        if (mWakefulness == WAKEFULNESS_ASLEEP || sQuiescent) {
             return DisplayPowerRequest.POLICY_OFF;
         }
 
@@ -2899,10 +2919,25 @@
         }
         if (reason.equals(PowerManager.REBOOT_RECOVERY)
                 || reason.equals(PowerManager.REBOOT_RECOVERY_UPDATE)) {
-            SystemProperties.set("sys.powerctl", "reboot,recovery");
-        } else {
-            SystemProperties.set("sys.powerctl", "reboot," + reason);
+            reason = "recovery";
         }
+
+        // If the reason is "quiescent", it means that the boot process should proceed
+        // without turning on the screen/lights.
+        // The "quiescent" property is sticky, meaning that any number
+        // of subsequent reboots should honor the property until it is reset.
+        if (reason.equals(PowerManager.REBOOT_QUIESCENT)) {
+            sQuiescent = true;
+            reason = "";
+        }
+
+        if (sQuiescent) {
+            // Pass the optional "quiescent" argument to the bootloader to let it know
+            // that it should not turn the screen/lights on.
+            reason = reason + ",quiescent";
+        }
+
+        SystemProperties.set("sys.powerctl", "reboot," + reason);
         try {
             Thread.sleep(20 * 1000L);
         } catch (InterruptedException e) {
diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java
index ad87a88..0fc1900 100644
--- a/services/core/java/com/android/server/vr/VrManagerInternal.java
+++ b/services/core/java/com/android/server/vr/VrManagerInternal.java
@@ -56,25 +56,27 @@
             int userId, @NonNull ComponentName calling);
 
     /**
-     * Set the current VR mode state immediately.
+     * Set whether the system has acquired a sleep token.
      *
-     * @param enabled {@code true} to enable VR mode.
-     * @param packageName The package name of the requested VrListenerService to bind.
-     * @param userId the user requesting the VrListenerService component.
-     * @param calling the component currently using VR mode, or null to leave unchanged.
+     * @param isAsleep is {@code true} if the device is asleep, or {@code false} otherwise.
      */
-    public abstract void setVrModeImmediate(boolean enabled, @NonNull ComponentName packageName,
-            int userId, @NonNull ComponentName calling);
+    public abstract void onSleepStateChanged(boolean isAsleep);
 
+    /**
+     * Set whether the display used for VR output is on.
+     *
+     * @param isScreenOn is {@code true} if the display is on and can receive commands,
+     *      or {@code false} otherwise.
+     */
+    public abstract void onScreenStateChanged(boolean isScreenOn);
 
-   /**
-    * Return NO_ERROR if the given package is installed on the device and enabled as a
-    * VrListenerService for the given current user, or a negative error code indicating a failure.
-    *
-    * @param packageName the name of the package to check, or null to select the default package.
-    * @return NO_ERROR if the given package is installed and is enabled, or a negative error code
-    *       given in {@link android.service.vr.VrModeException} on failure.
-    */
+    /**
+     * Return NO_ERROR if the given package is installed on the device and enabled as a
+     * VrListenerService for the given current user, or a negative error code indicating a failure.
+     *
+     * @param packageName the name of the package to check, or null to select the default package.
+     * @return NO_ERROR if the given package is installed and is enabled, or a negative error code
+     *       given in {@link android.service.vr.VrModeException} on failure.
+     */
     public abstract int hasVrPackage(@NonNull ComponentName packageName, int userId);
-
 }
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index fdadc8d..1083e0a 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -101,6 +101,14 @@
     private static final int PENDING_STATE_DELAY_MS = 300;
     private static final int EVENT_LOG_SIZE = 32;
     private static final int INVALID_APPOPS_MODE = -1;
+    /** Null set of sleep sleep flags. */
+    private static final int FLAG_NONE = 0;
+    /** Flag set when the device is not sleeping. */
+    private static final int FLAG_AWAKE = 1;
+    /** Flag set when the screen has been turned on. */
+    private static final int FLAG_SCREEN_ON = 2;
+    /** Flag indicating that all system sleep flags have been set.*/
+    private static final int FLAG_ALL = FLAG_AWAKE | FLAG_SCREEN_ON;
 
     private static native void initializeNative();
     private static native void setVrModeNative(boolean enabled);
@@ -110,6 +118,7 @@
     private final IBinder mOverlayToken = new Binder();
 
     // State protected by mLock
+    private boolean mVrModeAllowed;
     private boolean mVrModeEnabled;
     private EnabledComponentsObserver mComponentObserver;
     private ManagedApplicationService mCurrentVrService;
@@ -125,10 +134,64 @@
     private VrState mPendingState;
     private final ArrayDeque<VrState> mLoggingDeque = new ArrayDeque<>(EVENT_LOG_SIZE);
     private final NotificationAccessManager mNotifAccessManager = new NotificationAccessManager();
+    /** Tracks the state of the screen and keyguard UI.*/
+    private int mSystemSleepFlags = FLAG_NONE;
 
     private static final int MSG_VR_STATE_CHANGE = 0;
     private static final int MSG_PENDING_VR_STATE_CHANGE = 1;
 
+    /**
+     * Set whether VR mode may be enabled.
+     * <p/>
+     * If VR mode is not allowed to be enabled, calls to set VR mode will be cached.  When VR mode
+     * is again allowed to be enabled, the most recent cached state will be applied.
+     *
+     * @param allowed {@code true} if calling any of the setVrMode methods may cause the device to
+     *   enter VR mode.
+     */
+    private void setVrModeAllowedLocked(boolean allowed) {
+        if (mVrModeAllowed != allowed) {
+            mVrModeAllowed = allowed;
+            Slog.i(TAG, "VR mode is " + ((allowed) ? "allowed" : "disallowed"));
+            if (mVrModeAllowed) {
+                consumeAndApplyPendingStateLocked();
+            } else {
+                // Set pending state to current state.
+                mPendingState = (mVrModeEnabled && mCurrentVrService != null)
+                    ? new VrState(mVrModeEnabled, mCurrentVrService.getComponent(),
+                        mCurrentVrService.getUserId(), mCurrentVrModeComponent)
+                    : null;
+
+                // Unbind current VR service and do necessary callbacks.
+                updateCurrentVrServiceLocked(false, null, 0, null);
+            }
+        }
+    }
+
+    private void setSleepState(boolean isAsleep) {
+        synchronized(mLock) {
+
+            if (!isAsleep) {
+                mSystemSleepFlags |= FLAG_AWAKE;
+            } else {
+                mSystemSleepFlags &= ~FLAG_AWAKE;
+            }
+
+            setVrModeAllowedLocked(mSystemSleepFlags == FLAG_ALL);
+        }
+    }
+
+    private void setScreenOn(boolean isScreenOn) {
+        synchronized(mLock) {
+            if (isScreenOn) {
+                mSystemSleepFlags |= FLAG_SCREEN_ON;
+            } else {
+                mSystemSleepFlags &= ~FLAG_SCREEN_ON;
+            }
+            setVrModeAllowedLocked(mSystemSleepFlags == FLAG_ALL);
+        }
+    }
+
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
@@ -148,7 +211,9 @@
                 } break;
                 case MSG_PENDING_VR_STATE_CHANGE : {
                     synchronized(mLock) {
-                        VrManagerService.this.consumeAndApplyPendingStateLocked();
+                        if (mVrModeAllowed) {
+                           VrManagerService.this.consumeAndApplyPendingStateLocked();
+                        }
                     }
                 } break;
                 default :
@@ -268,8 +333,8 @@
             }
             mNotifAccessManager.update(enabledPackages);
 
-            if (mCurrentVrService == null) {
-                return; // No active services
+            if (!mVrModeAllowed) {
+                return; // Don't do anything, we shouldn't be in VR mode.
             }
 
             // If there is a pending state change, we'd better deal with that first
@@ -321,6 +386,7 @@
                 return;
             }
             pw.println("********* Dump of VrManagerService *********");
+            pw.println("VR mode is currently: " + ((mVrModeAllowed) ? "allowed" : "disallowed"));
             pw.println("Previous state transitions:\n");
             String tab = "  ";
             dumpStateTransitions(pw);
@@ -374,13 +440,17 @@
         @Override
         public void setVrMode(boolean enabled, ComponentName packageName, int userId,
                 ComponentName callingPackage) {
-            VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage, false);
+            VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage);
         }
 
         @Override
-        public void setVrModeImmediate(boolean enabled, ComponentName packageName, int userId,
-                ComponentName callingPackage) {
-            VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage, true);
+        public void onSleepStateChanged(boolean isAsleep) {
+            VrManagerService.this.setSleepState(isAsleep);
+        }
+
+        @Override
+        public void onScreenStateChanged(boolean isScreenOn) {
+            VrManagerService.this.setScreenOn(isScreenOn);
         }
 
         @Override
@@ -424,6 +494,10 @@
 
                 mComponentObserver.rebuildAll();
             }
+        } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
+            synchronized (mLock) {
+                mVrModeAllowed = true;
+            }
         }
     }
 
@@ -466,12 +540,16 @@
                     false, mOverlayToken, null, oldUserId);
         }
 
+        if (!mVrModeEnabled) {
+            return;
+        }
+
         // Apply the restrictions for the current user based on vr state
         String[] exemptions = (exemptedPackage == null) ? new String[0] :
                 new String[] { exemptedPackage };
 
         appOpsManager.setUserRestrictionForUser(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
-                mVrModeEnabled, mOverlayToken, exemptions, newUserId);
+                true, mOverlayToken, exemptions, newUserId);
     }
 
     private void updateDependentAppOpsLocked(String newVrServicePackage, int newUserId,
@@ -512,7 +590,8 @@
 
             boolean validUserComponent = (mComponentObserver.isValid(component, userId) ==
                     EnabledComponentsObserver.NO_ERROR);
-            if (!mVrModeEnabled && !enabled) {
+            boolean goingIntoVrMode = validUserComponent && enabled;
+            if (!mVrModeEnabled && !goingIntoVrMode) {
                 return validUserComponent; // Disabled -> Disabled transition does nothing.
             }
 
@@ -520,29 +599,37 @@
                     ? mCurrentVrService.getComponent().getPackageName() : null;
             final int oldUserId = mCurrentVrModeUser;
 
-            // Always send mode change events.
-            changeVrModeLocked(enabled);
+            // Notify system services and VR HAL of mode change.
+            changeVrModeLocked(goingIntoVrMode);
 
-            if (!enabled || !validUserComponent) {
-                // Unbind whatever is running
+            boolean nothingChanged = false;
+            if (!goingIntoVrMode) {
+                // Not going into VR mode, unbind whatever is running
                 if (mCurrentVrService != null) {
                     Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " +
                             mCurrentVrService.getUserId());
                     mCurrentVrService.disconnect();
                     mCurrentVrService = null;
+                } else {
+                    nothingChanged = true;
                 }
             } else {
+                // Going into VR mode
                 if (mCurrentVrService != null) {
-                    // Unbind any running service that doesn't match the component/user selection
+                    // Unbind any running service that doesn't match the latest component/user
+                    // selection.
                     if (mCurrentVrService.disconnectIfNotMatching(component, userId)) {
                         Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() +
                                 " for user " + mCurrentVrService.getUserId());
                         createAndConnectService(component, userId);
                         sendUpdatedCaller = true;
+                    } else {
+                        nothingChanged = true;
                     }
-                    // The service with the correct component/user is bound
+                    // The service with the correct component/user is already bound, do nothing.
                 } else {
-                    // Nothing was previously running, bind a new service
+                    // Nothing was previously running, bind a new service for the latest
+                    // component/user selection.
                     createAndConnectService(component, userId);
                     sendUpdatedCaller = true;
                 }
@@ -577,7 +664,10 @@
                     }
                 });
             }
-            logStateLocked();
+
+            if (!nothingChanged) {
+                logStateLocked();
+            }
 
             return validUserComponent;
         } finally {
@@ -663,16 +753,28 @@
     private void grantCoarseLocationPermissionIfNeeded(String pkg, int userId) {
         // Don't clobber the user if permission set in current state explicitly
         if (!isPermissionUserUpdated(Manifest.permission.ACCESS_COARSE_LOCATION, pkg, userId)) {
-            mContext.getPackageManager().grantRuntimePermission(pkg,
-                    Manifest.permission.ACCESS_COARSE_LOCATION, new UserHandle(userId));
+            try {
+                mContext.getPackageManager().grantRuntimePermission(pkg,
+                        Manifest.permission.ACCESS_COARSE_LOCATION, new UserHandle(userId));
+            } catch (IllegalArgumentException e) {
+                // Package was removed during update.
+                Slog.w(TAG, "Could not grant coarse location permission, package " + pkg
+                    + " was removed.");
+            }
         }
     }
 
     private void revokeCoarseLocationPermissionIfNeeded(String pkg, int userId) {
         // Don't clobber the user if permission set in current state explicitly
         if (!isPermissionUserUpdated(Manifest.permission.ACCESS_COARSE_LOCATION, pkg, userId)) {
-            mContext.getPackageManager().revokeRuntimePermission(pkg,
-                    Manifest.permission.ACCESS_COARSE_LOCATION, new UserHandle(userId));
+            try {
+                mContext.getPackageManager().revokeRuntimePermission(pkg,
+                        Manifest.permission.ACCESS_COARSE_LOCATION, new UserHandle(userId));
+            } catch (IllegalArgumentException e) {
+                // Package was removed during update.
+                Slog.w(TAG, "Could not revoke coarse location permission, package " + pkg
+                    + " was removed.");
+            }
         }
     }
 
@@ -772,7 +874,10 @@
                     mPendingState.targetPackageName, mPendingState.userId,
                     mPendingState.callingPackage);
             mPendingState = null;
+        } else {
+            updateCurrentVrServiceLocked(false, null, 0, null);
         }
+
     }
 
     private void logStateLocked() {
@@ -822,13 +927,20 @@
     /*
      * Implementation of VrManagerInternal calls.  These are callable from system services.
      */
-
     private void setVrMode(boolean enabled, @NonNull ComponentName targetPackageName,
-            int userId, @NonNull ComponentName callingPackage, boolean immediate) {
+            int userId, @NonNull ComponentName callingPackage) {
 
         synchronized (mLock) {
+            VrState pending = new VrState(enabled, targetPackageName, userId, callingPackage);
+            if (!mVrModeAllowed) {
+                // We're not allowed to be in VR mode.  Make this state pending.  This will be
+                // applied the next time we are allowed to enter VR mode unless it is superseded by
+                // another call.
+                mPendingState = pending;
+                return;
+            }
 
-            if (!enabled && mCurrentVrService != null && !immediate) {
+            if (!enabled && mCurrentVrService != null) {
                 // If we're transitioning out of VR mode, delay briefly to avoid expensive HAL calls
                 // and service bind/unbind in case we are immediately switching to another VR app.
                 if (mPendingState == null) {
@@ -836,7 +948,7 @@
                             PENDING_STATE_DELAY_MS);
                 }
 
-                mPendingState = new VrState(enabled, targetPackageName, userId, callingPackage);
+                mPendingState = pending;
                 return;
             } else {
                 mHandler.removeMessages(MSG_PENDING_VR_STATE_CHANGE);
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 00c37d2..6147885 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -17,6 +17,8 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.StackId;
+import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
+import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
@@ -45,6 +47,7 @@
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
 import static com.android.server.wm.WindowManagerService.logWithStack;
 
+import android.content.pm.ActivityInfo;
 import android.os.Debug;
 import com.android.internal.util.ToBooleanFunction;
 import com.android.server.input.InputApplicationHandle;
@@ -81,18 +84,18 @@
 
     @NonNull final AppWindowAnimator mAppAnimator;
 
-    final boolean voiceInteraction;
+    final boolean mVoiceInteraction;
 
     // TODO: Use getParent instead?
     Task mTask;
     /** @see WindowContainer#fillsParent() */
     private boolean mFillsParent;
     boolean layoutConfigChanges;
-    boolean showForAllUsers;
-    int targetSdk;
+    boolean mShowForAllUsers;
+    int mTargetSdk;
 
     // The input dispatching timeout for this application token in nanoseconds.
-    long inputDispatchingTimeoutNanos;
+    long mInputDispatchingTimeoutNanos;
 
     // These are used for determining when all windows associated with
     // an activity have been drawn, so they can be made visible together
@@ -152,7 +155,7 @@
     boolean mLaunchTaskBehind;
     boolean mEnteringAnimation;
 
-    boolean mAlwaysFocusable;
+    private boolean mAlwaysFocusable;
 
     boolean mAppStopped;
     int mRotationAnimationHint;
@@ -167,12 +170,31 @@
     ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
     ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>();
 
-    AppWindowToken(WindowManagerService service, IApplicationToken token, boolean _voiceInteraction,
-            DisplayContent displayContent) {
-        super(service, token != null ? token.asBinder() : null, TYPE_APPLICATION, true,
-                displayContent);
+    AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction,
+            DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen,
+            boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint,
+            int configChanges, boolean launchTaskBehind, boolean alwaysFocusable) {
+        this(service, token, voiceInteraction, dc);
+        mInputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
+        mFillsParent = fullscreen;
+        mShowForAllUsers = showForAllUsers;
+        mTargetSdk = targetSdk;
+        mOrientation = orientation;
+        layoutConfigChanges = (configChanges & (CONFIG_SCREEN_SIZE | CONFIG_ORIENTATION)) != 0;
+        mLaunchTaskBehind = launchTaskBehind;
+        mAlwaysFocusable = alwaysFocusable;
+        mRotationAnimationHint = rotationAnimationHint;
+
+        // Application tokens start out hidden.
+        hidden = true;
+        hiddenRequested = true;
+    }
+
+    AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction,
+            DisplayContent dc) {
+        super(service, token != null ? token.asBinder() : null, TYPE_APPLICATION, true, dc);
         appToken = token;
-        voiceInteraction = _voiceInteraction;
+        mVoiceInteraction = voiceInteraction;
         mInputApplicationHandle = new InputApplicationHandle(this);
         mAppAnimator = new AppWindowAnimator(this, service);
     }
@@ -407,7 +429,7 @@
 
         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app token: " + this);
 
-        boolean delayed = setVisibility(null, false, TRANSIT_UNSET, true, voiceInteraction);
+        boolean delayed = setVisibility(null, false, TRANSIT_UNSET, true, mVoiceInteraction);
 
         mService.mOpeningApps.remove(this);
         mService.mUnknownAppVisibilityController.appRemoved(this);
@@ -1350,7 +1372,7 @@
     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.println(prefix + "app=true mVoiceInteraction=" + mVoiceInteraction);
         }
         pw.print(prefix); pw.print("task="); pw.println(mTask);
         pw.print(prefix); pw.print(" mFillsParent="); pw.print(mFillsParent);
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index f8b461e..e6bc7f4 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -390,9 +390,8 @@
                 inputMethodManagerInternal.hideCurrentInputMethod();
                 mImeHideRequested = true;
             }
-        } else if (setMinimizedDockedStack(false)) {
-            mService.mWindowPlacerLocked.performSurfacePlacement();
         }
+        setMinimizedDockedStack(false, false /* animate */);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 0e4add8..36520a9 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -327,7 +327,7 @@
         // Global drags are limited to system windows, and windows for apps that are targeting N and
         // above.
         return targetWin.mAppToken == null
-                || targetWin.mAppToken.targetSdk >= Build.VERSION_CODES.N;
+                || targetWin.mAppToken.mTargetSdk >= Build.VERSION_CODES.N;
     }
 
     /* helper - send a ACTION_DRAG_STARTED event only if the window has not
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 495be09..3fbe36f 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -258,7 +258,7 @@
                 if (! abort) {
                     // The activity manager declined to abort dispatching.
                     // Wait a bit longer and timeout again later.
-                    return appWindowToken.inputDispatchingTimeoutNanos;
+                    return appWindowToken.mInputDispatchingTimeoutNanos;
                 }
             } catch (RemoteException ex) {
             }
@@ -504,7 +504,7 @@
         } else {
             final InputApplicationHandle handle = newApp.mInputApplicationHandle;
             handle.name = newApp.toString();
-            handle.dispatchingTimeoutNanos = newApp.inputDispatchingTimeoutNanos;
+            handle.dispatchingTimeoutNanos = newApp.mInputDispatchingTimeoutNanos;
 
             mService.mInputManager.setFocusedApplication(handle);
         }
@@ -591,8 +591,6 @@
 
         private void updateInputWindows(boolean inDrag) {
 
-            clearInputWindowHandlesLw();
-
             // TODO: multi-display
             navInputConsumer = getInputConsumer(INPUT_CONSUMER_NAVIGATION, DEFAULT_DISPLAY);
             pipInputConsumer = getInputConsumer(INPUT_CONSUMER_PIP, DEFAULT_DISPLAY);
@@ -614,6 +612,8 @@
 
             // Send windows to native code.
             mService.mInputManager.setInputWindows(mInputWindowHandles);
+
+            clearInputWindowHandlesLw();
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 0ad4e0a..34633c2 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -18,12 +18,13 @@
 
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.util.TypedValue.COMPLEX_UNIT_DIP;
-import static android.view.Display.DEFAULT_DISPLAY;
 
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.animation.ValueAnimator;
+import android.app.RemoteAction;
+import android.content.pm.ParceledListSlice;
 import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.PointF;
@@ -41,12 +42,13 @@
 import android.view.IPinnedStackController;
 import android.view.IPinnedStackListener;
 
-import com.android.internal.os.BackgroundThread;
 import com.android.internal.policy.PipMotionHelper;
 import com.android.internal.policy.PipSnapAlgorithm;
 import com.android.server.UiThread;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Holds the common state of the pinned stack between the system and SystemUI.
@@ -70,10 +72,14 @@
     // States that affect how the PIP can be manipulated
     private boolean mInInteractiveMode;
     private boolean mIsMinimized;
+    private boolean mIsSnappingToEdge;
     private boolean mIsImeShowing;
     private int mImeHeight;
     private ValueAnimator mBoundsAnimator = null;
 
+    // The set of actions that are currently allowed on the PiP activity
+    private ArrayList<RemoteAction> mActions = new ArrayList<>();
+
     // Used to calculate stack bounds across rotations
     private final DisplayInfo mDisplayInfo = new DisplayInfo();
 
@@ -113,6 +119,7 @@
         @Override
         public void setSnapToEdge(final boolean snapToEdge) {
             mHandler.post(() -> {
+                mIsSnappingToEdge = snapToEdge;
                 mSnapAlgorithm.setSnapToEdge(snapToEdge);
             });
         }
@@ -171,6 +178,9 @@
             listener.onListenerRegistered(mCallbacks);
             mPinnedStackListener = listener;
             notifyBoundsChanged(mIsImeShowing);
+            notifyMinimizeChanged(mIsMinimized);
+            notifySnapToEdgeChanged(mIsSnappingToEdge);
+            notifyActionsChanged(mActions);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to register pinned stack listener", e);
         }
@@ -315,7 +325,16 @@
     }
 
     /**
-     * Sends a broadcast that the PIP movement bounds have changed.
+     * Sets the current set of actions.
+     */
+    void setActions(List<RemoteAction> actions) {
+        mActions.clear();
+        mActions.addAll(actions);
+        notifyActionsChanged(mActions);
+    }
+
+    /**
+     * Notifies listeners that the PIP movement bounds have changed.
      */
     private void notifyBoundsChanged(boolean adjustedForIme) {
         if (mPinnedStackListener != null) {
@@ -328,6 +347,45 @@
     }
 
     /**
+     * Notifies listeners that the PIP minimized state has changed.
+     */
+    private void notifyMinimizeChanged(boolean isMinimized) {
+        if (mPinnedStackListener != null) {
+            try {
+                mPinnedStackListener.onMinimizedStateChanged(isMinimized);
+            } catch (RemoteException e) {
+                Slog.e(TAG_WM, "Error delivering minimize changed event.", e);
+            }
+        }
+    }
+
+    /**
+     * Notifies listeners that the PIP snap-to-edge state has changed.
+     */
+    private void notifySnapToEdgeChanged(boolean isSnappingToEdge) {
+        if (mPinnedStackListener != null) {
+            try {
+                mPinnedStackListener.onSnapToEdgeStateChanged(isSnappingToEdge);
+            } catch (RemoteException e) {
+                Slog.e(TAG_WM, "Error delivering snap-to-edge changed event.", e);
+            }
+        }
+    }
+
+    /**
+     * Notifies listeners that the PIP actions have changed.
+     */
+    private void notifyActionsChanged(List<RemoteAction> actions) {
+        if (mPinnedStackListener != null) {
+            try {
+                mPinnedStackListener.onActionsChanged(new ParceledListSlice(actions));
+            } catch (RemoteException e) {
+                Slog.e(TAG_WM, "Error delivering actions changed event.", e);
+            }
+        }
+    }
+
+    /**
      * @return the bounds on the screen that the PIP can be visible in.
      */
     private void getInsetBounds(Rect outRect) {
@@ -355,5 +413,16 @@
         pw.println(prefix + "  mIsImeShowing=" + mIsImeShowing);
         pw.println(prefix + "  mInInteractiveMode=" + mInInteractiveMode);
         pw.println(prefix + "  mIsMinimized=" + mIsMinimized);
+        if (mActions.isEmpty()) {
+            pw.println(prefix + "  mActions=[]");
+        } else {
+            pw.println(prefix + "  mActions=[");
+            for (int i = 0; i < mActions.size(); i++) {
+                RemoteAction action = mActions.get(i);
+                pw.print(prefix + "    Action[" + i + "]: ");
+                action.dump("", pw);
+            }
+            pw.println(prefix + "  ]");
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 612af75..aa6e3c7 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -88,12 +88,15 @@
     private boolean mIsOnTopLauncher;
 
     Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
-            Configuration overrideConfig, boolean isOnTopLauncher) {
+            Configuration overrideConfig, boolean isOnTopLauncher, int resizeMode,
+            boolean homeTask) {
         mTaskId = taskId;
         mStack = stack;
         mUserId = userId;
         mService = service;
         mIsOnTopLauncher = isOnTopLauncher;
+        mResizeMode = resizeMode;
+        mHomeTask = homeTask;
         setBounds(bounds, overrideConfig);
     }
 
@@ -101,7 +104,8 @@
         return mStack.getDisplayContent();
     }
 
-    void addAppToken(int addPos, AppWindowToken wtoken, int resizeMode, boolean homeTask) {
+    @Override
+    void addChild(AppWindowToken wtoken, int addPos) {
         final int lastPos = mChildren.size();
         if (addPos >= lastPos) {
             addPos = lastPos;
@@ -118,11 +122,9 @@
         if (parent != null) {
             parent.removeChild(wtoken);
         }
-        addChild(wtoken, addPos);
+        super.addChild(wtoken, addPos);
         wtoken.mTask = this;
         mDeferRemoval = false;
-        mResizeMode = resizeMode;
-        mHomeTask = homeTask;
     }
 
     private boolean hasWindowsAlive() {
@@ -536,7 +538,7 @@
 
     boolean showForAllUsers() {
         final int tokensCount = mChildren.size();
-        return (tokensCount != 0) && mChildren.get(tokensCount - 1).showForAllUsers;
+        return (tokensCount != 0) && mChildren.get(tokensCount - 1).mShowForAllUsers;
     }
 
     boolean inFreeformWorkspace() {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 02376e9..4a1c067 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -129,7 +129,7 @@
 
     /** Adds the input window container has a child of this container at the input index. */
     @CallSuper
-    protected void addChild(E child, int index) {
+    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()
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e68960c..577e5a0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -26,13 +26,13 @@
 import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
+import android.app.RemoteAction;
 import android.app.admin.DevicePolicyManager;
 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.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.CompatibilityInfo;
@@ -238,6 +238,7 @@
 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 java.lang.Integer.MAX_VALUE;
 
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
@@ -1480,7 +1481,7 @@
         // Try using the target SDK of the root window
         if (attachedWindow != null) {
             return attachedWindow.mAppToken != null
-                    && attachedWindow.mAppToken.targetSdk > Build.VERSION_CODES.N_MR1;
+                    && attachedWindow.mAppToken.mTargetSdk > Build.VERSION_CODES.N_MR1;
         } else {
             // Otherwise, look at the package
             try {
@@ -2439,28 +2440,11 @@
         }
     }
 
-    private Task createTaskLocked(int taskId, int stackId, int userId, AppWindowToken atoken,
-            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);
-        if (stack == null) {
-            throw new IllegalArgumentException("createTaskLocked: invalid stackId=" + stackId);
-        }
-        EventLog.writeEvent(WM_TASK_CREATED, taskId, stackId);
-        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;
-    }
-
     @Override
-    public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
-            int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId,
+    public void addAppToken(int addPos, IApplicationToken token, int taskId,
+            int requestedOrientation, boolean fullscreen, boolean showForAllUsers,
             int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
-            Rect taskBounds, Configuration overrideConfig, int taskResizeMode,
-            boolean alwaysFocusable, boolean homeTask, int targetSdkVersion,
-            int rotationAnimationHint, boolean isOnTopLauncher) {
+            boolean alwaysFocusable, int targetSdkVersion, int rotationAnimationHint) {
         if (!checkCallingPermission(MANAGE_APP_TOKENS, "addAppToken()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
         }
@@ -2486,42 +2470,24 @@
                 return;
             }
 
-            final TaskStack stack = mStackIdToStack.get(stackId);
-            if (stack == null) {
-                throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId);
-            }
-
-            atoken = new AppWindowToken(this, token, voiceInteraction, stack.getDisplayContent());
-            atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
-            atoken.setFillsParent(fullscreen);
-            atoken.showForAllUsers = showForAllUsers;
-            atoken.targetSdk = targetSdkVersion;
-            atoken.setOrientation(requestedOrientation);
-            atoken.layoutConfigChanges = (configChanges &
-                    (ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;
-            atoken.mLaunchTaskBehind = launchTaskBehind;
-            atoken.mAlwaysFocusable = alwaysFocusable;
-            if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
-                    + " to stack=" + stackId + " task=" + taskId + " at " + addPos);
-            atoken.mRotationAnimationHint = rotationAnimationHint;
-
             Task task = mTaskIdToTask.get(taskId);
             if (task == null) {
-                task = createTaskLocked(taskId, stackId, userId, atoken, taskBounds, overrideConfig,
-                        isOnTopLauncher);
+                throw new IllegalArgumentException("addAppToken: invalid taskId=" + taskId);
             }
-            task.addAppToken(addPos, atoken, taskResizeMode, homeTask);
 
-            // Application tokens start out hidden.
-            atoken.hidden = true;
-            atoken.hiddenRequested = true;
+            atoken = new AppWindowToken(this, token, voiceInteraction, task.getDisplayContent(),
+                    inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
+                    requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
+                    alwaysFocusable);
+            if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
+                    + " task=" + taskId + " at " + addPos);
+
+            task.addChild(atoken, addPos);
         }
     }
 
     @Override
-    public void setAppTask(IBinder token, int taskId, int stackId, Rect taskBounds,
-            Configuration overrideConfig, int taskResizeMode, boolean homeTask,
-            boolean isOnTopLauncher) {
+    public void addAppToTask(IBinder token, int taskId) {
         if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppTask()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
         }
@@ -2533,12 +2499,40 @@
                 return;
             }
 
-            Task newTask = mTaskIdToTask.get(taskId);
-            if (newTask == null) {
-                newTask = createTaskLocked(taskId, stackId, atoken.mTask.mUserId, atoken,
-                        taskBounds, overrideConfig, isOnTopLauncher);
+            Task task = mTaskIdToTask.get(taskId);
+            if (task == null) {
+                throw new IllegalArgumentException("setAppTask: invalid taskId=" + taskId);
             }
-            newTask.addAppToken(Integer.MAX_VALUE /* at top */, atoken, taskResizeMode, homeTask);
+            task.addChild(atoken, MAX_VALUE /* at top */);
+        }
+    }
+
+    public void addTask(int taskId, int stackId, int userId, Rect bounds,
+            Configuration overrideConfig, int resizeMode, boolean homeTask, boolean isOnTopLauncher,
+            boolean toTop, boolean showForAllUsers) {
+        if (!checkCallingPermission(MANAGE_APP_TOKENS, "addTask()")) {
+            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
+        }
+
+        synchronized(mWindowMap) {
+            Task task = mTaskIdToTask.get(taskId);
+            if (task != null) {
+                throw new IllegalArgumentException(
+                        "addTask: Attempt to add already existing task=" + task);
+            }
+
+            if (DEBUG_STACK) Slog.i(TAG_WM, "createTaskLocked: taskId=" + taskId
+                    + " stackId=" + stackId + " bounds=" + bounds);
+
+            final TaskStack stack = mStackIdToStack.get(stackId);
+            if (stack == null) {
+                throw new IllegalArgumentException("addTask: invalid stackId=" + stackId);
+            }
+            EventLog.writeEvent(WM_TASK_CREATED, taskId, stackId);
+            task = new Task(taskId, stack, userId, this, bounds, overrideConfig, isOnTopLauncher,
+                    resizeMode, homeTask);
+            mTaskIdToTask.put(taskId, task);
+            stack.addTask(task, toTop, showForAllUsers);
         }
     }
 
@@ -3203,7 +3197,7 @@
             }
 
             final long origId = Binder.clearCallingIdentity();
-            wtoken.setVisibility(null, visible, TRANSIT_UNSET, true, wtoken.voiceInteraction);
+            wtoken.setVisibility(null, visible, TRANSIT_UNSET, true, wtoken.mVoiceInteraction);
             wtoken.updateReportedVisibilityLocked();
             Binder.restoreCallingIdentity(origId);
         }
@@ -3412,22 +3406,6 @@
         }
     }
 
-    public void setPictureInPictureAspectRatio(float aspectRatio) {
-        synchronized (mWindowMap) {
-            if (!mSupportsPictureInPicture) {
-                return;
-            }
-
-            final TaskStack stack = mStackIdToStack.get(PINNED_STACK_ID);
-            if (stack == null) {
-                return;
-            }
-
-            animateResizePinnedStack(getPictureInPictureBounds(
-                    stack.getDisplayContent().getDisplayId(), aspectRatio), -1);
-        }
-    }
-
     public Rect getPictureInPictureBounds(int displayId, float aspectRatio) {
         synchronized (mWindowMap) {
             if (!mSupportsPictureInPicture) {
@@ -3454,6 +3432,36 @@
     }
 
     /**
+     * Sets the current picture-in-picture aspect ratio.
+     */
+    public void setPictureInPictureAspectRatio(float aspectRatio) {
+        synchronized (mWindowMap) {
+            final TaskStack stack = mStackIdToStack.get(PINNED_STACK_ID);
+            if (!mSupportsPictureInPicture || stack == null) {
+                return;
+            }
+
+            final int displayId = stack.getDisplayContent().getDisplayId();
+            final Rect toBounds = getPictureInPictureBounds(displayId, aspectRatio);
+            animateResizePinnedStack(toBounds, -1 /* duration */);
+        }
+    }
+
+    /**
+     * Sets the current picture-in-picture actions.
+     */
+    public void setPictureInPictureActions(List<RemoteAction> actions) {
+        synchronized (mWindowMap) {
+            final TaskStack stack = mStackIdToStack.get(PINNED_STACK_ID);
+            if (!mSupportsPictureInPicture || stack == null) {
+                return;
+            }
+
+            stack.getDisplayContent().getPinnedStackController().setActions(actions);
+        }
+    }
+
+    /**
      * Place a TaskStack on a DisplayContent. Will create a new TaskStack if none is found with
      * specified stackId.
      * @param stackId The unique identifier of the new stack.
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index e2027fd..3daad43 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -124,7 +124,6 @@
 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;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION;
@@ -634,7 +633,7 @@
         }
         mIsFloatingLayer = mIsImWindow || mIsWallpaper;
 
-        if (mAppToken != null && mAppToken.showForAllUsers) {
+        if (mAppToken != null && mAppToken.mShowForAllUsers) {
             // Windows for apps that can show for all users should also show when the device is
             // locked.
             mAttrs.flags |= FLAG_SHOW_WHEN_LOCKED;
@@ -1035,7 +1034,7 @@
 
     @Override
     public boolean isVoiceInteraction() {
-        return mAppToken != null && mAppToken.voiceInteraction;
+        return mAppToken != null && mAppToken.mVoiceInteraction;
     }
 
     boolean setReportResizeHints() {
@@ -1225,7 +1224,7 @@
 
     public long getInputDispatchingTimeoutNanos() {
         return mAppToken != null
-                ? mAppToken.inputDispatchingTimeoutNanos
+                ? mAppToken.mInputDispatchingTimeoutNanos
                 : WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
     }
 
@@ -2887,7 +2886,7 @@
         // Child windows are evaluated based on their parent window.
         final WindowState win = getTopParentWindow();
         if (win.mAttrs.type < FIRST_SYSTEM_WINDOW
-                && win.mAppToken != null && win.mAppToken.showForAllUsers) {
+                && win.mAppToken != null && win.mAppToken.mShowForAllUsers) {
 
             // All window frames that are fullscreen extend above status bar, but some don't extend
             // below navigation bar. Thus, check for display frame for top/left and stable frame for
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index de80837..1aabd5e 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -5,8 +5,6 @@
 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.PRIVATE_FLAG_KEYGUARD;
-import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
 import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_CLOSE;
@@ -27,7 +25,6 @@
 import static com.android.server.wm.AppTransition.TRANSIT_WALLPAPER_OPEN;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
 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.SHOW_LIGHT_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -35,7 +32,6 @@
 import static com.android.server.wm.WindowManagerService.H.DO_TRAVERSAL;
 import static com.android.server.wm.WindowManagerService.H.NOTIFY_APP_TRANSITION_STARTING;
 import static com.android.server.wm.WindowManagerService.H.REPORT_WINDOWS_CHANGE;
-import static com.android.server.wm.WindowManagerService.H.UPDATE_DOCKED_STACK_DIVIDER;
 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;
@@ -53,7 +49,6 @@
 import android.view.DisplayInfo;
 import android.view.Surface;
 import android.view.SurfaceControl;
-import android.view.View;
 import android.view.WindowManager.LayoutParams;
 import android.view.animation.Animation;
 
@@ -293,7 +288,7 @@
                 }
             }
 
-            voiceInteraction |= wtoken.voiceInteraction;
+            voiceInteraction |= wtoken.mVoiceInteraction;
 
             if (wtoken.fillsParent()) {
                 final WindowState ws = wtoken.findMainWindow();
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 50a6095..3e8e420 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -74,6 +74,7 @@
     libutils \
     android.hardware.audio.common@2.0 \
     android.hardware.gnss@1.0 \
+    android.hardware.ir@1.0 \
     android.hardware.light@2.0 \
     android.hardware.power@1.0 \
     android.hardware.thermal@1.0 \
diff --git a/services/core/jni/com_android_server_ConsumerIrService.cpp b/services/core/jni/com_android_server_ConsumerIrService.cpp
index 7104870..5906e6b 100644
--- a/services/core/jni/com_android_server_ConsumerIrService.cpp
+++ b/services/core/jni/com_android_server_ConsumerIrService.cpp
@@ -23,87 +23,70 @@
 #include <stdlib.h>
 #include <utils/misc.h>
 #include <utils/Log.h>
-#include <hardware/hardware.h>
-#include <hardware/consumerir.h>
+#include <android/hardware/ir/1.0/IConsumerIr.h>
 #include <ScopedPrimitiveArray.h>
 
+using ::android::hardware::ir::V1_0::IConsumerIr;
+using ::android::hardware::ir::V1_0::ConsumerIrFreqRange;
+using ::android::hardware::hidl_vec;
+
 namespace android {
 
-static jlong halOpen(JNIEnv* /* env */, jobject /* obj */) {
-    hw_module_t const* module;
-    consumerir_device_t *dev;
-    int err;
+static sp<IConsumerIr> mHal;
 
-    err = hw_get_module(CONSUMERIR_HARDWARE_MODULE_ID, &module);
-    if (err != 0) {
-        ALOGE("Can't open consumer IR HW Module, error: %d", err);
-        return 0;
-    }
-
-    err = module->methods->open(module, CONSUMERIR_TRANSMITTER,
-            (hw_device_t **) &dev);
-    if (err < 0) {
-        ALOGE("Can't open consumer IR transmitter, error: %d", err);
-        return 0;
-    }
-
-    return reinterpret_cast<jlong>(dev);
+static jboolean halOpen(JNIEnv* /* env */, jobject /* obj */) {
+    // TODO(b/31632518)
+    mHal = IConsumerIr::getService("consumerir");
+    return mHal != nullptr;
 }
 
-static jint halTransmit(JNIEnv *env, jobject /* obj */, jlong halObject,
-   jint carrierFrequency, jintArray pattern) {
-    int ret;
-
-    consumerir_device_t *dev = reinterpret_cast<consumerir_device_t*>(halObject);
+static jint halTransmit(JNIEnv *env, jobject /* obj */, jint carrierFrequency,
+   jintArray pattern) {
     ScopedIntArrayRO cPattern(env, pattern);
     if (cPattern.get() == NULL) {
         return -EINVAL;
     }
-    jsize patternLength = cPattern.size();
+    hidl_vec<int32_t> patternVec;
+    patternVec.setToExternal(const_cast<int32_t*>(cPattern.get()), cPattern.size());
 
-    ret = dev->transmit(dev, carrierFrequency, cPattern.get(), patternLength);
-
-    return reinterpret_cast<jint>(ret);
+    bool success = mHal->transmit(carrierFrequency, patternVec, cPattern.size());
+    return success ? 0 : -1;
 }
 
-static jintArray halGetCarrierFrequencies(JNIEnv *env, jobject /* obj */,
-    jlong halObject) {
-    consumerir_device_t *dev = reinterpret_cast<consumerir_device_t*>(halObject);
-    consumerir_freq_range_t *ranges;
+static jintArray halGetCarrierFrequencies(JNIEnv *env, jobject /* obj */) {
     int len;
+    hidl_vec<ConsumerIrFreqRange> ranges;
+    bool success;
 
-    len = dev->get_num_carrier_freqs(dev);
-    if (len <= 0)
-        return NULL;
+    auto cb = [&](bool s, hidl_vec<ConsumerIrFreqRange> vec) {
+            ranges = vec;
+            success = s;
+    };
+    mHal->getCarrierFreqs(cb);
 
-    ranges = new consumerir_freq_range_t[len];
-
-    len = dev->get_carrier_freqs(dev, len, ranges);
-    if (len <= 0) {
-        delete[] ranges;
+    if (!success) {
         return NULL;
     }
+    len = ranges.size();
 
     int i;
     ScopedIntArrayRW freqsOut(env, env->NewIntArray(len*2));
     jint *arr = freqsOut.get();
     if (arr == NULL) {
-        delete[] ranges;
         return NULL;
     }
     for (i = 0; i < len; i++) {
-        arr[i*2] = ranges[i].min;
-        arr[i*2+1] = ranges[i].max;
+        arr[i*2] = static_cast<jint>(ranges[i].min);
+        arr[i*2+1] = static_cast<jint>(ranges[i].max);
     }
 
-    delete[] ranges;
     return freqsOut.getJavaArray();
 }
 
 static const JNINativeMethod method_table[] = {
-    { "halOpen", "()J", (void *)halOpen },
-    { "halTransmit", "(JI[I)I", (void *)halTransmit },
-    { "halGetCarrierFrequencies", "(J)[I", (void *)halGetCarrierFrequencies},
+    { "halOpen", "()Z", (void *)halOpen },
+    { "halTransmit", "(I[I)I", (void *)halTransmit },
+    { "halGetCarrierFrequencies", "()[I", (void *)halGetCarrierFrequencies},
 };
 
 int register_android_server_ConsumerIrService(JNIEnv *env) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index aafc432..3281bd6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -153,7 +153,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
 import com.android.internal.util.ParcelableString;
@@ -4806,6 +4805,20 @@
 
             long ident = mInjector.binderClearCallingIdentity();
             try {
+                final String restriction;
+                if (userHandle == UserHandle.USER_SYSTEM) {
+                    restriction = UserManager.DISALLOW_FACTORY_RESET;
+                } else if (isManagedProfile(userHandle)) {
+                    restriction = UserManager.DISALLOW_REMOVE_MANAGED_PROFILE;
+                } else {
+                    restriction = UserManager.DISALLOW_REMOVE_USER;
+                }
+                if (isAdminAffectedByRestriction(
+                        admin.info.getComponent(), restriction, userHandle)) {
+                    throw new SecurityException("Cannot wipe data. " + restriction
+                            + " restriction is set for user " + userHandle);
+                }
+
                 if ((flags & WIPE_RESET_PROTECTION_DATA) != 0) {
                     if (!isDeviceOwner(admin.info.getComponent(), userHandle)) {
                         throw new SecurityException(
@@ -4817,34 +4830,21 @@
                         manager.wipe();
                     }
                 }
+
                 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, force);
+                        "DevicePolicyManager.wipeData() from " + source, /*force=*/ true);
             } finally {
                 mInjector.binderRestoreCallingIdentity(ident);
             }
         }
     }
 
-    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) {
+    private void wipeDeviceOrUserLocked(
+            boolean wipeExtRequested, final int userHandle, String reason, boolean force) {
+        // TODO If split user is enabled and the device owner is set in the primary user (rather
+        // than system), we should probably trigger factory reset. Current code just remove
+        // that user (but still clears FRP...)
         if (userHandle == UserHandle.USER_SYSTEM) {
             wipeDataLocked(wipeExtRequested, reason, force);
         } else {
@@ -4857,10 +4857,12 @@
                             am.switchUser(UserHandle.USER_SYSTEM);
                         }
 
-                        boolean isManagedProfile = isManagedProfile(userHandle);
-                        if (!mUserManager.removeUser(userHandle)) {
+                        boolean userRemoved = force
+                                ? mUserManagerInternal.removeUserEvenWhenDisallowed(userHandle)
+                                : mUserManager.removeUser(userHandle);
+                        if (!userRemoved) {
                             Slog.w(LOG_TAG, "Couldn't remove user " + userHandle);
-                        } else if (isManagedProfile) {
+                        } else if (isManagedProfile(userHandle)) {
                             sendWipeProfileNotification();
                         }
                     } catch (RemoteException re) {
@@ -5948,7 +5950,8 @@
         }
         synchronized (this) {
             enforceCanSetDeviceOwnerLocked(admin, userId);
-            if (getActiveAdminUncheckedLocked(admin, userId) == null
+            final ActiveAdmin activeAdmin = getActiveAdminUncheckedLocked(admin, userId);
+            if (activeAdmin == null
                     || getUserData(userId).mRemovingAdmins.contains(admin)) {
                 throw new IllegalArgumentException("Not active admin: " + admin);
             }
@@ -5975,12 +5978,23 @@
             mOwners.writeDeviceOwner();
             updateDeviceOwnerLocked();
             setDeviceOwnerSystemPropertyLocked();
-            Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED);
+
+            // STOPSHIP(b/31952368) Also set this restriction for existing DOs on OTA to Android OC.
+            final Set<String> restrictions =
+                    UserRestrictionsUtils.getDefaultEnabledForDeviceOwner();
+            if (!restrictions.isEmpty()) {
+                for (String restriction : restrictions) {
+                    activeAdmin.ensureUserRestrictions().putBoolean(restriction, true);
+                }
+                saveUserRestrictionsLocked(userId);
+            }
 
             ident = mInjector.binderClearCallingIdentity();
             try {
                 // TODO Send to system too?
-                mContext.sendBroadcastAsUser(intent, new UserHandle(userId));
+                mContext.sendBroadcastAsUser(
+                        new Intent(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED),
+                        UserHandle.of(userId));
             } finally {
                 mInjector.binderRestoreCallingIdentity(ident);
             }
@@ -6176,6 +6190,7 @@
             mOwners.setProfileOwner(who, ownerName, userHandle);
             mOwners.writeProfileOwner(userHandle);
             Slog.i(LOG_TAG, "Profile owner set: " + who + " on user " + userHandle);
+
             return true;
         }
     }
@@ -7486,28 +7501,41 @@
     @Override
     public boolean removeUser(ComponentName who, UserHandle userHandle) {
         Preconditions.checkNotNull(who, "ComponentName is null");
-        UserHandle callingUserHandle = mInjector.binderGetCallingUserHandle();
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
         }
+
+        final int callingUserId = mInjector.userHandleGetCallingUserId();
         final long id = mInjector.binderClearCallingIdentity();
         try {
-            int restrictionSource = mUserManager.getUserRestrictionSource(
-                    UserManager.DISALLOW_REMOVE_USER, callingUserHandle);
-            if (restrictionSource != UserManager.RESTRICTION_NOT_SET
-                    && restrictionSource != UserManager.RESTRICTION_SOURCE_DEVICE_OWNER) {
+            String restriction = isManagedProfile(userHandle.getIdentifier())
+                    ? UserManager.DISALLOW_REMOVE_MANAGED_PROFILE
+                    : UserManager.DISALLOW_REMOVE_USER;
+            if (isAdminAffectedByRestriction(who, restriction, callingUserId)) {
                 Log.w(LOG_TAG, "The device owner cannot remove a user because "
-                        + "DISALLOW_REMOVE_USER is enabled, and was not set by the device "
-                        + "owner");
+                        + restriction + " is enabled, and was not set by the device owner");
                 return false;
             }
-            return mUserManagerInternal.removeUserEvenWhenDisallowed(
-                    userHandle.getIdentifier());
+            return mUserManagerInternal.removeUserEvenWhenDisallowed(userHandle.getIdentifier());
         } finally {
             mInjector.binderRestoreCallingIdentity(id);
         }
     }
 
+    private boolean isAdminAffectedByRestriction(
+            ComponentName admin, String userRestriction, int userId) {
+        switch(mUserManager.getUserRestrictionSource(userRestriction, UserHandle.of(userId))) {
+            case UserManager.RESTRICTION_NOT_SET:
+                return false;
+            case UserManager.RESTRICTION_SOURCE_DEVICE_OWNER:
+                return !isDeviceOwner(admin, userId);
+            case UserManager.RESTRICTION_SOURCE_PROFILE_OWNER:
+                return !isProfileOwner(admin, userId);
+            default:
+                return true;
+        }
+    }
+
     @Override
     public boolean switchUser(ComponentName who, UserHandle userHandle) {
         Preconditions.checkNotNull(who, "ComponentName is null");
@@ -7613,14 +7641,16 @@
 
             // Save the restriction to ActiveAdmin.
             activeAdmin.ensureUserRestrictions().putBoolean(key, enabledFromThisOwner);
-            saveSettingsLocked(userHandle);
-
-            pushUserRestrictions(userHandle);
-
-            sendChangedNotification(userHandle);
+            saveUserRestrictionsLocked(userHandle);
         }
     }
 
+    private void saveUserRestrictionsLocked(int userId) {
+        saveSettingsLocked(userId);
+        pushUserRestrictions(userId);
+        sendChangedNotification(userId);
+    }
+
     private void pushUserRestrictions(int userId) {
         synchronized (this) {
             final Bundle global;
@@ -8862,26 +8892,33 @@
         if (!hasFeatureManagedUsers()) {
             return CODE_MANAGED_USERS_NOT_SUPPORTED;
         }
-        synchronized (this) {
-            if (mOwners.hasDeviceOwner()) {
-                // STOPSHIP Only allow creating a managed profile if allowed by the device
-                // owner. http://b/31952368
-                if (mInjector.userManagerIsSplitSystemUser()) {
-                    if (callingUserId == UserHandle.USER_SYSTEM) {
-                        // Managed-profiles cannot be setup on the system user.
-                        return CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER;
-                    }
-                }
-            }
+        if (callingUserId == UserHandle.USER_SYSTEM
+                && mInjector.userManagerIsSplitSystemUser()) {
+            // Managed-profiles cannot be setup on the system user.
+            return CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER;
         }
         if (getProfileOwner(callingUserId) != null) {
             // Managed user cannot have a managed profile.
             return CODE_USER_HAS_PROFILE_OWNER;
         }
-        boolean canRemoveProfile =
-                !mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER);
         final long ident = mInjector.binderClearCallingIdentity();
         try {
+             /* STOPSHIP(b/31952368) Reinstate a check similar to this once ManagedProvisioning
+                   uses checkProvisioningPreCondition (see ag/1607846) and passes the packageName
+                   there. In isProvisioningAllowed we should check isCallerDeviceOwner, but for
+                   managed provisioning we need to check the package that is going to be set as PO
+                if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE)) {
+                    if (!isCallerDeviceOwner(callingUid)
+                            || isAdminAffectedByRestriction(mOwners.getDeviceOwnerComponent(),
+                                    UserManager.DISALLOW_ADD_MANAGED_PROFILE, callingUserId)) {
+                    // Caller is not DO or the restriction was set by the system.
+                    return false;
+                    }
+                } */
+            // TODO: Allow it if the caller is the DO? DO could just call removeUser() before
+            // provisioning, so not strictly required...
+            boolean canRemoveProfile = !mUserManager.hasUserRestriction(
+                        UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, UserHandle.of(callingUserId));
             if (!mUserManager.canAddMoreManagedProfiles(callingUserId, canRemoveProfile)) {
                 return CODE_CANNOT_ADD_MANAGED_PROFILE;
             }
@@ -9702,9 +9739,8 @@
             final int callingUserId = mInjector.userHandleGetCallingUserId();
             final boolean isCallerDeviceOwner = isDeviceOwner(callingOwner);
             final boolean isCallerManagedProfile = isManagedProfile(callingUserId);
-            if (!isCallerDeviceOwner && !isCallerManagedProfile
-                    /* STOPSHIP(b/32326223) Reinstate when setAffiliationIds is public
-                    ||   !isAffiliatedUser(callingUserId) */) {
+            if ((!isCallerDeviceOwner && !isCallerManagedProfile)
+                    || !isUserAffiliatedWithDevice(callingUserId)) {
                 return targetUsers;
             }
 
@@ -9724,8 +9760,7 @@
 
                         // Both must be the same package and be affiliated in order to bind.
                         if (callingOwnerPackage.equals(targetOwnerPackage)
-                            /* STOPSHIP(b/32326223) Reinstate when setAffiliationIds is public
-                               && isAffiliatedUser(userId)*/) {
+                               && isUserAffiliatedWithDevice(userId)) {
                             targetUsers.add(UserHandle.of(userId));
                         }
                     }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
index 8cb13da..49ae2bc3 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
@@ -34,6 +34,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * A class for managing network logging.
@@ -45,17 +46,17 @@
 
     private final DevicePolicyManagerService mDpm;
     private final PackageManagerInternal mPm;
+    private final AtomicBoolean mIsLoggingEnabled = new AtomicBoolean(false);
 
     private IIpConnectivityMetrics mIpConnectivityMetrics;
     private ServiceThread mHandlerThread;
     private NetworkLoggingHandler mNetworkLoggingHandler;
-    private boolean mIsLoggingEnabled;
 
     private final INetdEventCallback mNetdEventCallback = new INetdEventCallback.Stub() {
         @Override
         public void onDnsEvent(String hostname, String[] ipAddresses, int ipAddressesCount,
                 long timestamp, int uid) {
-            if (!mIsLoggingEnabled) {
+            if (!mIsLoggingEnabled.get()) {
                 return;
             }
             DnsEvent dnsEvent = new DnsEvent(hostname, ipAddresses, ipAddressesCount,
@@ -65,7 +66,7 @@
 
         @Override
         public void onConnectEvent(String ipAddr, int port, long timestamp, int uid) {
-            if (!mIsLoggingEnabled) {
+            if (!mIsLoggingEnabled.get()) {
                 return;
             }
             ConnectEvent connectEvent = new ConnectEvent(ipAddr, port, mPm.getNameForUid(uid),
@@ -116,7 +117,7 @@
                         mDpm);
                 mNetworkLoggingHandler.scheduleBatchFinalization(
                         NetworkLoggingHandler.BATCH_FINALIZATION_TIMEOUT_MS);
-                mIsLoggingEnabled = true;
+                mIsLoggingEnabled.set(true);
                 return true;
             } else {
                 return false;
@@ -130,7 +131,7 @@
     boolean stopNetworkLogging() {
         Log.d(TAG, "Stopping network logging");
         // stop the logging regardless of whether we fail to unregister listener
-        mIsLoggingEnabled = false;
+        mIsLoggingEnabled.set(false);
         try {
             if (!checkIpConnectivityMetricsService()) {
                 // the IIpConnectivityMetrics service should have been present at this point
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 02dc5fb..be13499 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -32,6 +32,7 @@
 import android.os.Environment;
 import android.os.FactoryTest;
 import android.os.FileUtils;
+import android.os.IIncidentManager;
 import android.os.Looper;
 import android.os.PowerManager;
 import android.os.RemoteException;
@@ -273,7 +274,7 @@
             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, uptimeMillis);
             MetricsLogger.histogram(null, "boot_system_server_init", uptimeMillis);
             // Also report when first stage of init has started
-            long initStartNs = SystemProperties.getLong("init.start", -1);
+            long initStartNs = SystemProperties.getLong("ro.boottime.init", -1);
             if (initStartNs >= 0) {
                 MetricsLogger.histogram(null, "boot_android_init", (int)(initStartNs / 1000000));
             }
@@ -1635,6 +1636,19 @@
                 }
                 traceEnd();
 
+                traceBeginAndSlog("IncidentDaemonReady");
+                try {
+                    // TODO: Switch from checkService to getService once it's always
+                    // in the build and should reliably be there.
+                    final IIncidentManager incident = IIncidentManager.Stub.asInterface(
+                            ServiceManager.checkService("incident"));
+                    if (incident != null) incident.systemRunning();
+                } catch (Throwable e) {
+                    reportWtf("Notifying incident daemon running", e);
+                }
+                traceEnd();
+                
+
                 traceEnd();  // PhaseActivityManagerReady
             }
         });
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
index ef4bc02..d90a4a2 100644
--- a/services/net/java/android/net/dhcp/DhcpPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
@@ -7,6 +7,7 @@
 import android.os.Build;
 import android.os.SystemProperties;
 import android.system.OsConstants;
+import android.text.TextUtils;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.UnsupportedEncodingException;
@@ -25,8 +26,10 @@
  * Defines basic data and operations needed to build and use packets for the
  * DHCP protocol.  Subclasses create the specific packets used at each
  * stage of the negotiation.
+ *
+ * @hide
  */
-abstract class DhcpPacket {
+public abstract class DhcpPacket {
     protected static final String TAG = "DhcpPacket";
 
     // dhcpcd has a minimum lease of 20 seconds, but DhcpStateMachine would refuse to wake up the
@@ -629,7 +632,8 @@
     protected void addCommonClientTlvs(ByteBuffer buf) {
         addTlv(buf, DHCP_MAX_MESSAGE_SIZE, (short) MAX_LENGTH);
         addTlv(buf, DHCP_VENDOR_CLASS_ID, getVendorId());
-        addTlv(buf, DHCP_HOST_NAME, getHostname());
+        final String hn = getHostname();
+        if (!TextUtils.isEmpty(hn)) addTlv(buf, DHCP_HOST_NAME, hn);
     }
 
     /**
diff --git a/services/net/java/android/net/ip/ConnectivityPacketTracker.java b/services/net/java/android/net/ip/ConnectivityPacketTracker.java
new file mode 100644
index 0000000..884a8a7
--- /dev/null
+++ b/services/net/java/android/net/ip/ConnectivityPacketTracker.java
@@ -0,0 +1,148 @@
+/*
+ * 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.ip;
+
+import static android.system.OsConstants.*;
+
+import android.net.NetworkUtils;
+import android.net.util.BlockingSocketReader;
+import android.net.util.ConnectivityPacketSummary;
+import android.os.Handler;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.PacketSocketAddress;
+import android.util.Log;
+import android.util.LocalLog;
+
+import libcore.io.IoBridge;
+import libcore.util.HexEncoding;
+
+import java.io.FileDescriptor;
+import java.io.InterruptedIOException;
+import java.io.IOException;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+
+
+/**
+ * Critical connectivity packet tracking daemon.
+ *
+ * Tracks ARP, DHCPv4, and IPv6 RS/RA/NS/NA packets.
+ *
+ * This class's constructor, start() and stop() methods must only be called
+ * from the same thread on which the passed in |log| is accessed.
+ *
+ * Log lines include a hexdump of the packet, which can be decoded via:
+ *
+ *     echo -n H3XSTR1NG | sed -e 's/\([0-9A-F][0-9A-F]\)/\1 /g' -e 's/^/000000 /'
+ *                       | text2pcap - -
+ *                       | tcpdump -n -vv -e -r -
+ *
+ * @hide
+ */
+public class ConnectivityPacketTracker {
+    private static final String TAG = ConnectivityPacketTracker.class.getSimpleName();
+    private static final boolean DBG = false;
+    private static final String MARK_START = "--- START ---";
+    private static final String MARK_STOP = "--- STOP ---";
+
+    private final String mTag;
+    private final Handler mHandler;
+    private final LocalLog mLog;
+    private final BlockingSocketReader mPacketListener;
+
+    public ConnectivityPacketTracker(NetworkInterface netif, LocalLog log) {
+        final String ifname;
+        final int ifindex;
+        final byte[] hwaddr;
+        final int mtu;
+
+        try {
+            ifname = netif.getName();
+            ifindex = netif.getIndex();
+            hwaddr = netif.getHardwareAddress();
+            mtu = netif.getMTU();
+        } catch (NullPointerException|SocketException e) {
+            throw new IllegalArgumentException("bad network interface", e);
+        }
+
+        mTag = TAG + "." + ifname;
+        mHandler = new Handler();
+        mLog = log;
+        mPacketListener = new PacketListener(ifindex, hwaddr, mtu);
+    }
+
+    public void start() {
+        mLog.log(MARK_START);
+        mPacketListener.start();
+    }
+
+    public void stop() {
+        mPacketListener.stop();
+        mLog.log(MARK_STOP);
+    }
+
+    private final class PacketListener extends BlockingSocketReader {
+        private final int mIfIndex;
+        private final byte mHwAddr[];
+
+        PacketListener(int ifindex, byte[] hwaddr, int mtu) {
+            super(mtu);
+            mIfIndex = ifindex;
+            mHwAddr = hwaddr;
+        }
+
+        @Override
+        protected FileDescriptor createSocket() {
+            FileDescriptor s = null;
+            try {
+                // TODO: Evaluate switching to SOCK_DGRAM and changing the
+                // BlockingSocketReader's read() to recvfrom(), so that this
+                // might work on non-ethernet-like links (via SLL).
+                s = Os.socket(AF_PACKET, SOCK_RAW, 0);
+                NetworkUtils.attachControlPacketFilter(s, ARPHRD_ETHER);
+                Os.bind(s, new PacketSocketAddress((short) ETH_P_ALL, mIfIndex));
+            } catch (ErrnoException | IOException e) {
+                logError("Failed to create packet tracking socket: ", e);
+                closeSocket(s);
+                return null;
+            }
+            return s;
+        }
+
+        @Override
+        protected void handlePacket(byte[] recvbuf, int length) {
+            final String summary = ConnectivityPacketSummary.summarize(
+                    mHwAddr, recvbuf, length);
+            if (summary == null) return;
+
+            if (DBG) Log.d(mTag, summary);
+            addLogEntry(summary +
+                        "\n[" + new String(HexEncoding.encode(recvbuf, 0, length)) + "]");
+        }
+
+        @Override
+        protected void logError(String msg, Exception e) {
+            Log.e(mTag, msg, e);
+            addLogEntry(msg + e);
+        }
+
+        private void addLogEntry(String entry) {
+            mHandler.post(() -> mLog.log(entry));
+        }
+    }
+}
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 39f14e5..87018ec 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -374,6 +374,7 @@
     private static final int EVENT_DHCPACTION_TIMEOUT = 10;
 
     private static final int MAX_LOG_RECORDS = 500;
+    private static final int MAX_PACKET_RECORDS = 100;
 
     private static final boolean NO_CALLBACKS = false;
     private static final boolean SEND_CALLBACKS = true;
@@ -399,6 +400,7 @@
     private final WakeupMessage mDhcpActionTimeoutAlarm;
     private final AvoidBadWifiTracker mAvoidBadWifiTracker;
     private final LocalLog mLocalLog;
+    private final LocalLog mConnectivityPacketLog;
     private final MessageHandlingLogger mMsgStateLogger;
     private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
 
@@ -438,6 +440,10 @@
         mCallback = new LoggingCallbackWrapper(callback);
         mNwService = nwService;
 
+        mLocalLog = new LocalLog(MAX_LOG_RECORDS);
+        mConnectivityPacketLog = new LocalLog(MAX_PACKET_RECORDS);
+        mMsgStateLogger = new MessageHandlingLogger();
+
         mNetlinkTracker = new NetlinkTracker(
                 mInterfaceName,
                 new NetlinkTracker.Callback() {
@@ -451,48 +457,79 @@
                 super.interfaceAdded(iface);
                 if (mClatInterfaceName.equals(iface)) {
                     mCallback.setNeighborDiscoveryOffload(false);
+                } else if (!mInterfaceName.equals(iface)) {
+                    return;
                 }
+
+                final String msg = "interfaceAdded(" + iface +")";
+                logMsg(msg);
             }
 
             @Override
             public void interfaceRemoved(String iface) {
                 super.interfaceRemoved(iface);
+                // TODO: Also observe mInterfaceName going down and take some
+                // kind of appropriate action.
                 if (mClatInterfaceName.equals(iface)) {
                     // TODO: consider sending a message to the IpManager main
                     // StateMachine thread, in case "NDO enabled" state becomes
                     // tied to more things that 464xlat operation.
                     mCallback.setNeighborDiscoveryOffload(true);
+                } else if (!mInterfaceName.equals(iface)) {
+                    return;
                 }
+
+                final String msg = "interfaceRemoved(" + iface +")";
+                logMsg(msg);
+            }
+
+            private void logMsg(String msg) {
+                Log.d(mTag, msg);
+                getHandler().post(() -> { mLocalLog.log("OBSERVED " + msg); });
             }
         };
 
-        try {
-            mNwService.registerObserver(mNetlinkTracker);
-        } catch (RemoteException e) {
-            Log.e(mTag, "Couldn't register NetlinkTracker: " + e.toString());
-        }
+        mLinkProperties = new LinkProperties();
+        mLinkProperties.setInterfaceName(mInterfaceName);
 
-        mAvoidBadWifiTracker = new AvoidBadWifiTracker(mContext, getHandler());
-
-        resetLinkProperties();
+        mAvoidBadWifiTracker = new AvoidBadWifiTracker(mContext, getHandler(),
+                () -> { mLocalLog.log("OBSERVED AvoidBadWifi changed"); });
 
         mProvisioningTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
                 mTag + ".EVENT_PROVISIONING_TIMEOUT", EVENT_PROVISIONING_TIMEOUT);
         mDhcpActionTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
                 mTag + ".EVENT_DHCPACTION_TIMEOUT", EVENT_DHCPACTION_TIMEOUT);
 
-        // Super simple StateMachine.
+        // Anything the StateMachine may access must have been instantiated
+        // before this point.
+        configureAndStartStateMachine();
+
+        // Anything that may send messages to the StateMachine must only be
+        // configured to do so after the StateMachine has started (above).
+        startStateMachineUpdaters();
+    }
+
+    private void configureAndStartStateMachine() {
         addState(mStoppedState);
         addState(mStartedState);
             addState(mRunningState, mStartedState);
         addState(mStoppingState);
 
         setInitialState(mStoppedState);
-        mLocalLog = new LocalLog(MAX_LOG_RECORDS);
-        mMsgStateLogger = new MessageHandlingLogger();
+
         super.start();
     }
 
+    private void startStateMachineUpdaters() {
+        try {
+            mNwService.registerObserver(mNetlinkTracker);
+        } catch (RemoteException e) {
+            Log.e(mTag, "Couldn't register NetlinkTracker: " + e.toString());
+        }
+
+        mAvoidBadWifiTracker.start();
+    }
+
     @Override
     protected void onQuitting() {
         mCallback.onQuit();
@@ -501,6 +538,7 @@
     // Shut down this IpManager instance altogether.
     public void shutdown() {
         stop();
+        mAvoidBadWifiTracker.shutdown();
         quit();
     }
 
@@ -574,7 +612,7 @@
         }
 
         IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
-        pw.println("APF dump:");
+        pw.println(mTag + " APF dump:");
         pw.increaseIndent();
         // Thread-unsafe access to mApfFilter but just used for debugging.
         ApfFilter apfFilter = mApfFilter;
@@ -590,6 +628,12 @@
         pw.increaseIndent();
         mLocalLog.readOnlyLocalLog().dump(fd, pw, args);
         pw.decreaseIndent();
+
+        pw.println();
+        pw.println(mTag + " connectivity packet log:");
+        pw.increaseIndent();
+        mConnectivityPacketLog.readOnlyLocalLog().dump(fd, pw, args);
+        pw.decreaseIndent();
     }
 
 
@@ -1185,6 +1229,7 @@
     }
 
     class RunningState extends State {
+        private ConnectivityPacketTracker mPacketTracker;
         private boolean mDhcpActionInFlight;
 
         @Override
@@ -1197,6 +1242,9 @@
                 mCallback.setFallbackMulticastFilter(mMulticastFiltering);
             }
 
+            mPacketTracker = createPacketTracker();
+            if (mPacketTracker != null) mPacketTracker.start();
+
             if (mConfiguration.mEnableIPv6 && !startIPv6()) {
                 doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6);
                 transitionTo(mStoppingState);
@@ -1231,6 +1279,11 @@
                 mDhcpClient.doQuit();
             }
 
+            if (mPacketTracker != null) {
+                mPacketTracker.stop();
+                mPacketTracker = null;
+            }
+
             if (mApfFilter != null) {
                 mApfFilter.shutdown();
                 mApfFilter = null;
@@ -1239,6 +1292,14 @@
             resetLinkProperties();
         }
 
+        private ConnectivityPacketTracker createPacketTracker() {
+            try {
+                return new ConnectivityPacketTracker(mNetworkInterface, mConnectivityPacketLog);
+            } catch (IllegalArgumentException e) {
+                return null;
+            }
+        }
+
         private void ensureDhcpAction() {
             if (!mDhcpActionInFlight) {
                 mCallback.onPreDhcpAction();
diff --git a/services/net/java/android/net/util/AvoidBadWifiTracker.java b/services/net/java/android/net/util/AvoidBadWifiTracker.java
index c14e811..2abaeb1 100644
--- a/services/net/java/android/net/util/AvoidBadWifiTracker.java
+++ b/services/net/java/android/net/util/AvoidBadWifiTracker.java
@@ -57,7 +57,11 @@
     private final Context mContext;
     private final Handler mHandler;
     private final Runnable mReevaluateRunnable;
+    private final Uri mUri;
+    private final ContentResolver mResolver;
     private final SettingObserver mSettingObserver;
+    private final BroadcastReceiver mBroadcastReceiver;
+
     private volatile boolean mAvoidBadWifi = true;
 
     public AvoidBadWifiTracker(Context ctx, Handler handler) {
@@ -68,19 +72,36 @@
         mContext = ctx;
         mHandler = handler;
         mReevaluateRunnable = () -> { if (update() && cb != null) cb.run(); };
+        mUri = Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI);
+        mResolver = mContext.getContentResolver();
         mSettingObserver = new SettingObserver();
-
-        final IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
-        mContext.registerReceiverAsUser(new BroadcastReceiver() {
+        mBroadcastReceiver = new BroadcastReceiver() {
+            @Override
             public void onReceive(Context context, Intent intent) {
                 reevaluate();
             }
-        }, UserHandle.ALL, intentFilter, null, null);
+        };
 
         update();
     }
 
+    public void start() {
+        mResolver.registerContentObserver(mUri, false, mSettingObserver);
+
+        final IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+        mContext.registerReceiverAsUser(
+                mBroadcastReceiver, UserHandle.ALL, intentFilter, null, null);
+
+        reevaluate();
+    }
+
+    public void shutdown() {
+        mResolver.unregisterContentObserver(mSettingObserver);
+
+        mContext.unregisterReceiver(mBroadcastReceiver);
+    }
+
     public boolean currentValue() {
         return mAvoidBadWifi;
     }
@@ -100,8 +121,7 @@
     }
 
     public String getSettingsValue() {
-        final ContentResolver resolver = mContext.getContentResolver();
-        return Settings.Global.getString(resolver, NETWORK_AVOID_BAD_WIFI);
+        return Settings.Global.getString(mResolver, NETWORK_AVOID_BAD_WIFI);
     }
 
     @VisibleForTesting
@@ -117,12 +137,8 @@
     }
 
     private class SettingObserver extends ContentObserver {
-        private final Uri mUri = Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI);
-
         public SettingObserver() {
             super(null);
-            final ContentResolver resolver = mContext.getContentResolver();
-            resolver.registerContentObserver(mUri, false, this);
         }
 
         @Override
diff --git a/services/net/java/android/net/util/BlockingSocketReader.java b/services/net/java/android/net/util/BlockingSocketReader.java
new file mode 100644
index 0000000..12fa1e5
--- /dev/null
+++ b/services/net/java/android/net/util/BlockingSocketReader.java
@@ -0,0 +1,155 @@
+/*
+ * 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.annotation.Nullable;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+
+import libcore.io.IoBridge;
+
+import java.io.FileDescriptor;
+import java.io.InterruptedIOException;
+import java.io.IOException;
+
+
+/**
+ * A thread that reads from a socket and passes the received packets to a
+ * subclass's handlePacket() method.  The packet receive buffer is recycled
+ * on every read call, so subclasses should make any copies they would like
+ * inside their handlePacket() implementation.
+ *
+ * All public methods may be called from any thread.
+ *
+ * @hide
+ */
+public abstract class BlockingSocketReader {
+    public static final int DEFAULT_RECV_BUF_SIZE = 2 * 1024;
+
+    private final byte[] mPacket;
+    private final Thread mThread;
+    private volatile FileDescriptor mSocket;
+    private volatile boolean mRunning;
+    private volatile long mPacketsReceived;
+
+    // Make it slightly easier for subclasses to properly close a socket
+    // without having to know this incantation.
+    public static final void closeSocket(@Nullable FileDescriptor fd) {
+        try {
+            IoBridge.closeAndSignalBlockedThreads(fd);
+        } catch (IOException ignored) {}
+    }
+
+    protected BlockingSocketReader() {
+        this(DEFAULT_RECV_BUF_SIZE);
+    }
+
+    protected BlockingSocketReader(int recvbufsize) {
+        if (recvbufsize < DEFAULT_RECV_BUF_SIZE) {
+            recvbufsize = DEFAULT_RECV_BUF_SIZE;
+        }
+        mPacket = new byte[recvbufsize];
+        mThread = new Thread(() -> { mainLoop(); });
+    }
+
+    public final boolean start() {
+        if (mSocket != null) return false;
+
+        try {
+            mSocket = createSocket();
+        } catch (Exception e) {
+            logError("Failed to create socket: ", e);
+            return false;
+        }
+
+        if (mSocket == null) return false;
+
+        mRunning = true;
+        mThread.start();
+        return true;
+    }
+
+    public final void stop() {
+        mRunning = false;
+        closeSocket(mSocket);
+        mSocket = null;
+    }
+
+    public final boolean isRunning() { return mRunning; }
+
+    public final long numPacketsReceived() { return mPacketsReceived; }
+
+    /**
+     * Subclasses MUST create the listening socket here, including setting
+     * all desired socket options, interface or address/port binding, etc.
+     */
+    protected abstract FileDescriptor createSocket();
+
+    /**
+     * Called by the main loop for every packet.  Any desired copies of
+     * |recvbuf| should be made in here, and the underlying byte array is
+     * reused across all reads.
+     */
+    protected void handlePacket(byte[] recvbuf, int length) {}
+
+    /**
+     * Called by the main loop to log errors.  In some cases |e| may be null.
+     */
+    protected void logError(String msg, Exception e) {}
+
+    /**
+     * Called by the main loop just prior to exiting.
+     */
+    protected void onExit() {}
+
+    private final void mainLoop() {
+        while (isRunning()) {
+            final int bytesRead;
+
+            try {
+                // Blocking read.
+                // TODO: See if this can be converted to recvfrom.
+                bytesRead = Os.read(mSocket, mPacket, 0, mPacket.length);
+                if (bytesRead < 1) {
+                    if (isRunning()) logError("Socket closed, exiting", null);
+                    break;
+                }
+                mPacketsReceived++;
+            } catch (ErrnoException e) {
+                if (e.errno != OsConstants.EINTR) {
+                    if (isRunning()) logError("read error: ", e);
+                    break;
+                }
+                continue;
+            } catch (IOException ioe) {
+                if (isRunning()) logError("read error: ", ioe);
+                continue;
+            }
+
+            try {
+                handlePacket(mPacket, bytesRead);
+            } catch (Exception e) {
+                logError("Unexpected exception: ", e);
+                break;
+            }
+        }
+
+        stop();
+        onExit();
+    }
+}
diff --git a/services/net/java/android/net/util/ConnectivityPacketSummary.java b/services/net/java/android/net/util/ConnectivityPacketSummary.java
new file mode 100644
index 0000000..699ba5b
--- /dev/null
+++ b/services/net/java/android/net/util/ConnectivityPacketSummary.java
@@ -0,0 +1,375 @@
+/*
+ * 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.dhcp.DhcpPacket;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+import java.util.StringJoiner;
+
+import static android.system.OsConstants.*;
+import static android.net.util.NetworkConstants.*;
+
+
+/**
+ * Critical connectivity packet summarizing class.
+ *
+ * Outputs short descriptions of ARP, DHCPv4, and IPv6 RS/RA/NS/NA packets.
+ *
+ * @hide
+ */
+public class ConnectivityPacketSummary {
+    private static final String TAG = ConnectivityPacketSummary.class.getSimpleName();
+
+    private final byte[] mHwAddr;
+    private final byte[] mBytes;
+    private final int mLength;
+    private final ByteBuffer mPacket;
+    private final String mSummary;
+
+    public static String summarize(byte[] hwaddr, byte[] buffer) {
+        return summarize(hwaddr, buffer, buffer.length);
+    }
+
+    // Methods called herein perform some but by no means all error checking.
+    // They may throw runtime exceptions on malformed packets.
+    public static String summarize(byte[] hwaddr, byte[] buffer, int length) {
+        if ((hwaddr == null) || (hwaddr.length != ETHER_ADDR_LEN)) return null;
+        if (buffer == null) return null;
+        length = Math.min(length, buffer.length);
+        return (new ConnectivityPacketSummary(hwaddr, buffer, length)).toString();
+    }
+
+    private ConnectivityPacketSummary(byte[] hwaddr, byte[] buffer, int length) {
+        mHwAddr = hwaddr;
+        mBytes = buffer;
+        mLength = Math.min(length, mBytes.length);
+        mPacket = ByteBuffer.wrap(mBytes, 0, mLength);
+        mPacket.order(ByteOrder.BIG_ENDIAN);
+
+        final StringJoiner sj = new StringJoiner(" ");
+        // TODO: support other link-layers, or even no link-layer header.
+        parseEther(sj);
+        mSummary = sj.toString();
+    }
+
+    public String toString() {
+        return mSummary;
+    }
+
+    private void parseEther(StringJoiner sj) {
+        if (mPacket.remaining() < ETHER_HEADER_LEN) {
+            sj.add("runt:").add(asString(mPacket.remaining()));
+            return;
+        }
+
+        mPacket.position(ETHER_SRC_ADDR_OFFSET);
+        final ByteBuffer srcMac = (ByteBuffer) mPacket.slice().limit(ETHER_ADDR_LEN);
+        sj.add(ByteBuffer.wrap(mHwAddr).equals(srcMac) ? "TX" : "RX");
+        sj.add(getMacAddressString(srcMac));
+
+        mPacket.position(ETHER_DST_ADDR_OFFSET);
+        final ByteBuffer dstMac = (ByteBuffer) mPacket.slice().limit(ETHER_ADDR_LEN);
+        sj.add(">").add(getMacAddressString(dstMac));
+
+        mPacket.position(ETHER_TYPE_OFFSET);
+        final int etherType = asUint(mPacket.getShort());
+        switch (etherType) {
+            case ETHER_TYPE_ARP:
+                sj.add("arp");
+                parseARP(sj);
+                break;
+            case ETHER_TYPE_IPV4:
+                sj.add("ipv4");
+                parseIPv4(sj);
+                break;
+            case ETHER_TYPE_IPV6:
+                sj.add("ipv6");
+                parseIPv6(sj);
+                break;
+            default:
+                // Unknown ether type.
+                sj.add("ethtype").add(asString(etherType));
+                break;
+        }
+    }
+
+    private void parseARP(StringJoiner sj) {
+        if (mPacket.remaining() < ARP_PAYLOAD_LEN) {
+            sj.add("runt:").add(asString(mPacket.remaining()));
+            return;
+        }
+
+        if (asUint(mPacket.getShort()) != ARP_HWTYPE_ETHER ||
+            asUint(mPacket.getShort()) != ETHER_TYPE_IPV4 ||
+            asUint(mPacket.get()) != ETHER_ADDR_LEN ||
+            asUint(mPacket.get()) != IPV4_ADDR_LEN) {
+            sj.add("unexpected header");
+            return;
+        }
+
+        final int opCode = asUint(mPacket.getShort());
+
+        final String senderHwAddr = getMacAddressString(mPacket);
+        final String senderIPv4 = getIPv4AddressString(mPacket);
+        getMacAddressString(mPacket);  // target hardware address, unused
+        final String targetIPv4 = getIPv4AddressString(mPacket);
+
+        if (opCode == ARP_REQUEST) {
+            sj.add("who-has").add(targetIPv4);
+        } else if (opCode == ARP_REPLY) {
+            sj.add("reply").add(senderIPv4).add(senderHwAddr);
+        } else {
+            sj.add("unknown opcode").add(asString(opCode));
+        }
+    }
+
+    private void parseIPv4(StringJoiner sj) {
+        if (!mPacket.hasRemaining()) {
+            sj.add("runt");
+            return;
+        }
+
+        final int startOfIpLayer = mPacket.position();
+        final int ipv4HeaderLength = (mPacket.get(startOfIpLayer) & IPV4_IHL_MASK) * 4;
+        if (mPacket.remaining() < ipv4HeaderLength ||
+            mPacket.remaining() < IPV4_HEADER_MIN_LEN) {
+            sj.add("runt:").add(asString(mPacket.remaining()));
+            return;
+        }
+        final int startOfTransportLayer = startOfIpLayer + ipv4HeaderLength;
+
+        mPacket.position(startOfIpLayer + IPV4_FLAGS_OFFSET);
+        final int flagsAndFragment = asUint(mPacket.getShort());
+        final boolean isFragment = (flagsAndFragment & IPV4_FRAGMENT_MASK) != 0;
+
+        mPacket.position(startOfIpLayer + IPV4_PROTOCOL_OFFSET);
+        final int protocol = asUint(mPacket.get());
+
+        mPacket.position(startOfIpLayer + IPV4_SRC_ADDR_OFFSET);
+        final String srcAddr = getIPv4AddressString(mPacket);
+
+        mPacket.position(startOfIpLayer + IPV4_DST_ADDR_OFFSET);
+        final String dstAddr = getIPv4AddressString(mPacket);
+
+        sj.add(srcAddr).add(">").add(dstAddr);
+
+        mPacket.position(startOfTransportLayer);
+        if (protocol == IPPROTO_UDP) {
+            sj.add("udp");
+            if (isFragment) sj.add("fragment");
+            else parseUDP(sj);
+        } else {
+            sj.add("proto").add(asString(protocol));
+            if (isFragment) sj.add("fragment");
+        }
+    }
+
+    private void parseIPv6(StringJoiner sj) {
+        if (mPacket.remaining() < IPV6_HEADER_LEN) {
+            sj.add("runt:").add(asString(mPacket.remaining()));
+            return;
+        }
+
+        final int startOfIpLayer = mPacket.position();
+
+        mPacket.position(startOfIpLayer + IPV6_PROTOCOL_OFFSET);
+        final int protocol = asUint(mPacket.get());
+
+        mPacket.position(startOfIpLayer + IPV6_SRC_ADDR_OFFSET);
+        final String srcAddr = getIPv6AddressString(mPacket);
+        final String dstAddr = getIPv6AddressString(mPacket);
+
+        sj.add(srcAddr).add(">").add(dstAddr);
+
+        mPacket.position(startOfIpLayer + IPV6_HEADER_LEN);
+        if (protocol == IPPROTO_ICMPV6) {
+            sj.add("icmp6");
+            parseICMPv6(sj);
+        } else {
+            sj.add("proto").add(asString(protocol));
+        }
+    }
+
+    private void parseICMPv6(StringJoiner sj) {
+        if (mPacket.remaining() < ICMPV6_HEADER_MIN_LEN) {
+            sj.add("runt:").add(asString(mPacket.remaining()));
+            return;
+        }
+
+        final int icmp6Type = asUint(mPacket.get());
+        final int icmp6Code = asUint(mPacket.get());
+        mPacket.getShort();  // checksum, unused
+
+        switch (icmp6Type) {
+            case ICMPV6_ROUTER_SOLICITATION:
+                sj.add("rs");
+                parseICMPv6RouterSolicitation(sj);
+                break;
+            case ICMPV6_ROUTER_ADVERTISEMENT:
+                sj.add("ra");
+                parseICMPv6RouterAdvertisement(sj);
+                break;
+            case ICMPV6_NEIGHBOR_SOLICITATION:
+                sj.add("ns");
+                parseICMPv6NeighborMessage(sj);
+                break;
+            case ICMPV6_NEIGHBOR_ADVERTISEMENT:
+                sj.add("na");
+                parseICMPv6NeighborMessage(sj);
+                break;
+            default:
+                sj.add("type").add(asString(icmp6Type));
+                sj.add("code").add(asString(icmp6Code));
+                break;
+        }
+    }
+
+    private void parseICMPv6RouterSolicitation(StringJoiner sj) {
+        final int RESERVED = 4;
+        if (mPacket.remaining() < RESERVED) {
+            sj.add("runt:").add(asString(mPacket.remaining()));
+            return;
+        }
+
+        mPacket.position(mPacket.position() + RESERVED);
+        parseICMPv6NeighborDiscoveryOptions(sj);
+    }
+
+    private void parseICMPv6RouterAdvertisement(StringJoiner sj) {
+        final int FLAGS_AND_TIMERS = 3 * 4;
+        if (mPacket.remaining() < FLAGS_AND_TIMERS) {
+            sj.add("runt:").add(asString(mPacket.remaining()));
+            return;
+        }
+
+        mPacket.position(mPacket.position() + FLAGS_AND_TIMERS);
+        parseICMPv6NeighborDiscoveryOptions(sj);
+    }
+
+    private void parseICMPv6NeighborMessage(StringJoiner sj) {
+        final int RESERVED = 4;
+        final int minReq = RESERVED + IPV6_ADDR_LEN;
+        if (mPacket.remaining() < minReq) {
+            sj.add("runt:").add(asString(mPacket.remaining()));
+            return;
+        }
+
+        mPacket.position(mPacket.position() + RESERVED);
+        sj.add(getIPv6AddressString(mPacket));
+        parseICMPv6NeighborDiscoveryOptions(sj);
+    }
+
+    private void parseICMPv6NeighborDiscoveryOptions(StringJoiner sj) {
+        // All ND options are TLV, where T is one byte and L is one byte equal
+        // to the length of T + L + V in units of 8 octets.
+        while (mPacket.remaining() >= ICMPV6_ND_OPTION_MIN_LENGTH) {
+            final int ndType = asUint(mPacket.get());
+            final int ndLength = asUint(mPacket.get());
+            final int ndBytes = ndLength * ICMPV6_ND_OPTION_LENGTH_SCALING_FACTOR - 2;
+            if (mPacket.remaining() < ndBytes) break;
+            final int position = mPacket.position();
+
+            switch (ndType) {
+                    case ICMPV6_ND_OPTION_SLLA:
+                        sj.add("slla");
+                        sj.add(getMacAddressString(mPacket));
+                        break;
+                    case ICMPV6_ND_OPTION_TLLA:
+                        sj.add("tlla");
+                        sj.add(getMacAddressString(mPacket));
+                        break;
+                    case ICMPV6_ND_OPTION_MTU:
+                        sj.add("mtu");
+                        final short reserved = mPacket.getShort();
+                        sj.add(asString(mPacket.getInt()));
+                        break;
+                    default:
+                        // Skip.
+                        break;
+            }
+
+            mPacket.position(position + ndBytes);
+        }
+    }
+
+    private void parseUDP(StringJoiner sj) {
+        if (mPacket.remaining() < UDP_HEADER_LEN) {
+            sj.add("runt:").add(asString(mPacket.remaining()));
+            return;
+        }
+
+        final int previous = mPacket.position();
+        final int srcPort = asUint(mPacket.getShort());
+        final int dstPort = asUint(mPacket.getShort());
+        sj.add(asString(srcPort)).add(">").add(asString(dstPort));
+
+        mPacket.position(previous + UDP_HEADER_LEN);
+        if (srcPort == DHCP4_CLIENT_PORT || dstPort == DHCP4_CLIENT_PORT) {
+            sj.add("dhcp4");
+            parseDHCPv4(sj);
+        }
+    }
+
+    private void parseDHCPv4(StringJoiner sj) {
+        final DhcpPacket dhcpPacket;
+        try {
+            dhcpPacket = DhcpPacket.decodeFullPacket(mBytes, mLength, DhcpPacket.ENCAP_L2);
+            sj.add(dhcpPacket.toString());
+        } catch (DhcpPacket.ParseException e) {
+            sj.add("parse error: " + e);
+        }
+    }
+
+    private static String getIPv4AddressString(ByteBuffer ipv4) {
+        return getIpAddressString(ipv4, IPV4_ADDR_LEN);
+    }
+
+    private static String getIPv6AddressString(ByteBuffer ipv6) {
+        return getIpAddressString(ipv6, IPV6_ADDR_LEN);
+    }
+
+    private static String getIpAddressString(ByteBuffer ip, int byteLength) {
+        if (ip == null || ip.remaining() < byteLength) return "invalid";
+
+        byte[] bytes = new byte[byteLength];
+        ip.get(bytes, 0, byteLength);
+        try {
+            InetAddress addr = InetAddress.getByAddress(bytes);
+            return addr.getHostAddress();
+        } catch (UnknownHostException uhe) {
+            return "unknown";
+        }
+    }
+
+    private static String getMacAddressString(ByteBuffer mac) {
+        if (mac == null || mac.remaining() < ETHER_ADDR_LEN) return "invalid";
+
+        byte[] bytes = new byte[ETHER_ADDR_LEN];
+        mac.get(bytes, 0, bytes.length);
+        Byte[] printableBytes = new Byte[bytes.length];
+        int i = 0;
+        for (byte b : bytes) printableBytes[i++] = b;
+
+        final String MAC48_FORMAT = "%02x:%02x:%02x:%02x:%02x:%02x";
+        return String.format(MAC48_FORMAT, printableBytes);
+    }
+}
diff --git a/services/net/java/android/net/util/NetworkConstants.java b/services/net/java/android/net/util/NetworkConstants.java
new file mode 100644
index 0000000..362f757
--- /dev/null
+++ b/services/net/java/android/net/util/NetworkConstants.java
@@ -0,0 +1,146 @@
+/*
+ * 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 java.nio.ByteBuffer;
+
+
+/**
+ * Networking protocol constants.
+ *
+ * Includes:
+ *     - constants that describe packet layout
+ *     - various helper functions
+ *
+ * @hide
+ */
+public final class NetworkConstants {
+    private NetworkConstants() { throw new RuntimeException("no instance permitted"); }
+
+    /**
+     * Ethernet constants.
+     *
+     * See also:
+     *     - https://tools.ietf.org/html/rfc894
+     *     - https://tools.ietf.org/html/rfc7042
+     *     - http://www.iana.org/assignments/ethernet-numbers/ethernet-numbers.xhtml
+     *     - http://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml
+     */
+    public static final int ETHER_DST_ADDR_OFFSET = 0;
+    public static final int ETHER_SRC_ADDR_OFFSET = 6;
+    public static final int ETHER_ADDR_LEN = 6;
+
+    public static final int ETHER_TYPE_OFFSET = 12;
+    public static final int ETHER_TYPE_LENGTH = 2;
+    public static final int ETHER_TYPE_ARP  = 0x0806;
+    public static final int ETHER_TYPE_IPV4 = 0x0800;
+    public static final int ETHER_TYPE_IPV6 = 0x86dd;
+
+    public static final int ETHER_HEADER_LEN = 14;
+
+    private static final byte FF = asByte(0xff);
+    public static final byte[] ETHER_ADDR_BROADCAST = {
+        FF, FF, FF, FF, FF, FF
+    };
+
+    /**
+     * ARP constants.
+     *
+     * See also:
+     *     - https://tools.ietf.org/html/rfc826
+     *     - http://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml
+     */
+    public static final int ARP_PAYLOAD_LEN = 28;  // For Ethernet+IPv4.
+    public static final int ARP_REQUEST = 1;
+    public static final int ARP_REPLY   = 2;
+    public static final int ARP_HWTYPE_RESERVED_LO = 0;
+    public static final int ARP_HWTYPE_ETHER       = 1;
+    public static final int ARP_HWTYPE_RESERVED_HI = 0xffff;
+
+    /**
+     * IPv4 constants.
+     *
+     * See als:
+     *     - https://tools.ietf.org/html/rfc791
+     */
+    public static final int IPV4_HEADER_MIN_LEN = 20;
+    public static final int IPV4_IHL_MASK = 0xf;
+    public static final int IPV4_FLAGS_OFFSET = 6;
+    public static final int IPV4_FRAGMENT_MASK = 0x1fff;
+    public static final int IPV4_PROTOCOL_OFFSET = 9;
+    public static final int IPV4_SRC_ADDR_OFFSET = 12;
+    public static final int IPV4_DST_ADDR_OFFSET = 16;
+    public static final int IPV4_ADDR_LEN = 4;
+
+    /**
+     * IPv6 constants.
+     *
+     * See also:
+     *     - https://tools.ietf.org/html/rfc2460
+     */
+    public static final int IPV6_HEADER_LEN = 40;
+    public static final int IPV6_PROTOCOL_OFFSET = 6;
+    public static final int IPV6_SRC_ADDR_OFFSET = 8;
+    public static final int IPV6_DST_ADDR_OFFSET = 24;
+    public static final int IPV6_ADDR_LEN = 16;
+
+    /**
+     * ICMPv6 constants.
+     *
+     * See also:
+     *     - https://tools.ietf.org/html/rfc4443
+     *     - https://tools.ietf.org/html/rfc4861
+     */
+    public static final int ICMPV6_HEADER_MIN_LEN = 4;
+    public static final int ICMPV6_ROUTER_SOLICITATION    = 133;
+    public static final int ICMPV6_ROUTER_ADVERTISEMENT   = 134;
+    public static final int ICMPV6_NEIGHBOR_SOLICITATION  = 135;
+    public static final int ICMPV6_NEIGHBOR_ADVERTISEMENT = 136;
+
+    public static final int ICMPV6_ND_OPTION_MIN_LENGTH = 8;
+    public static final int ICMPV6_ND_OPTION_LENGTH_SCALING_FACTOR = 8;
+    public static final int ICMPV6_ND_OPTION_SLLA = 1;
+    public static final int ICMPV6_ND_OPTION_TLLA = 2;
+    public static final int ICMPV6_ND_OPTION_MTU  = 5;
+
+    /**
+     * UDP constants.
+     *
+     * See also:
+     *     - https://tools.ietf.org/html/rfc768
+     */
+    public static final int UDP_HEADER_LEN = 8;
+
+    /**
+     * DHCP(v4) constants.
+     *
+     * See also:
+     *     - https://tools.ietf.org/html/rfc2131
+     */
+    public static final int DHCP4_SERVER_PORT = 67;
+    public static final int DHCP4_CLIENT_PORT = 68;
+
+    /**
+     * Utility functions.
+     */
+    public static byte asByte(int i) { return (byte) i; }
+
+    public static String asString(int i) { return Integer.toString(i); }
+
+    public static int asUint(byte b) { return (b & 0xff); }
+    public static int asUint(short s) { return (s & 0xffff); }
+}
diff --git a/services/print/java/com/android/server/print/RemotePrintService.java b/services/print/java/com/android/server/print/RemotePrintService.java
index fa37576..fb78457 100644
--- a/services/print/java/com/android/server/print/RemotePrintService.java
+++ b/services/print/java/com/android/server/print/RemotePrintService.java
@@ -132,8 +132,6 @@
     }
 
     private void handleDestroy() {
-        throwIfDestroyed();
-
         // Stop tracking printers.
         stopTrackingAllPrinters();
 
@@ -174,7 +172,6 @@
     }
 
     private void handleOnAllPrintJobsHandled() {
-        throwIfDestroyed();
         mHasActivePrintJobs = false;
         if (!isBound()) {
             // The service is dead and neither has active jobs nor discovery
@@ -208,7 +205,6 @@
     }
 
     private void handleRequestCancelPrintJob(final PrintJobInfo printJob) {
-        throwIfDestroyed();
         if (!isBound()) {
             ensureBound();
             mPendingCommands.add(new Runnable() {
@@ -235,7 +231,6 @@
     }
 
     private void handleOnPrintJobQueued(final PrintJobInfo printJob) {
-        throwIfDestroyed();
         mHasActivePrintJobs = true;
         if (!isBound()) {
             ensureBound();
@@ -262,7 +257,6 @@
     }
 
     private void handleCreatePrinterDiscoverySession() {
-        throwIfDestroyed();
         mHasPrinterDiscoverySession = true;
         if (!isBound()) {
             ensureBound();
@@ -289,7 +283,6 @@
     }
 
     private void handleDestroyPrinterDiscoverySession() {
-        throwIfDestroyed();
         mHasPrinterDiscoverySession = false;
         if (!isBound()) {
             // The service is dead and neither has active jobs nor discovery
@@ -328,7 +321,6 @@
     }
 
     private void handleStartPrinterDiscovery(final List<PrinterId> priorityList) {
-        throwIfDestroyed();
         // Take a note that we are doing discovery.
         mDiscoveryPriorityList = new ArrayList<PrinterId>();
         if (priorityList != null) {
@@ -359,7 +351,6 @@
     }
 
     private void handleStopPrinterDiscovery() {
-        throwIfDestroyed();
         // We are not doing discovery anymore.
         mDiscoveryPriorityList = null;
         if (!isBound()) {
@@ -392,7 +383,6 @@
     }
 
     private void handleValidatePrinters(final List<PrinterId> printerIds) {
-        throwIfDestroyed();
         if (!isBound()) {
             ensureBound();
             mPendingCommands.add(new Runnable() {
@@ -419,23 +409,40 @@
     }
 
     /**
-     * Request the custom printer icon for a printer.
+     * Queue a request for a custom printer icon for a printer.
      *
      * @param printerId the id of the printer the icon should be loaded for
-     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon
      */
     public void requestCustomPrinterIcon(@NonNull PrinterId printerId) {
-        try {
-            if (isBound()) {
-                mPrintService.requestCustomPrinterIcon(printerId);
+        mHandler.obtainMessage(MyHandler.MSG_REQUEST_CUSTOM_PRINTER_ICON,
+                printerId).sendToTarget();
+    }
+
+    /**
+     * Request a custom printer icon for a printer.
+     *
+     * @param printerId the id of the printer the icon should be loaded for
+     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon
+     */
+    private void handleRequestCustomPrinterIcon(@NonNull PrinterId printerId) {
+        if (!isBound()) {
+            ensureBound();
+            mPendingCommands.add(() -> handleRequestCustomPrinterIcon(printerId));
+        } else {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "[user: " + mUserId + "] requestCustomPrinterIcon()");
             }
-        } catch (RemoteException re) {
-            Slog.e(LOG_TAG, "Error requesting icon for " + printerId, re);
+
+            try {
+                mPrintService.requestCustomPrinterIcon(printerId);
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG, "Error requesting icon for " + printerId, re);
+            }
         }
     }
 
     private void handleStartPrinterStateTracking(final @NonNull PrinterId printerId) {
-        throwIfDestroyed();
         // Take a note we are tracking the printer.
         if (mTrackedPrinterList == null) {
             mTrackedPrinterList = new ArrayList<PrinterId>();
@@ -467,7 +474,6 @@
     }
 
     private void handleStopPrinterStateTracking(final PrinterId printerId) {
-        throwIfDestroyed();
         // We are no longer tracking the printer.
         if (mTrackedPrinterList == null || !mTrackedPrinterList.remove(printerId)) {
             return;
@@ -581,12 +587,6 @@
         }
     }
 
-    private void throwIfDestroyed() {
-        if (mDestroyed) {
-            throw new IllegalStateException("Cannot interact with a destroyed service");
-        }
-    }
-
     private class RemoteServiceConneciton implements ServiceConnection {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
@@ -657,6 +657,7 @@
         public static final int MSG_ON_PRINT_JOB_QUEUED = 10;
         public static final int MSG_DESTROY = 11;
         public static final int MSG_BINDER_DIED = 12;
+        public static final int MSG_REQUEST_CUSTOM_PRINTER_ICON = 13;
 
         public MyHandler(Looper looper) {
             super(looper, null, false);
@@ -665,6 +666,11 @@
         @Override
         @SuppressWarnings("unchecked")
         public void handleMessage(Message message) {
+            if (mDestroyed) {
+                Slog.w(LOG_TAG, "Not handling " + message + " as service for " + mComponentName
+                        + " is already destroyed");
+                return;
+            }
             switch (message.what) {
                 case MSG_CREATE_PRINTER_DISCOVERY_SESSION: {
                     handleCreatePrinterDiscoverySession();
@@ -719,6 +725,11 @@
                 case MSG_BINDER_DIED: {
                     handleBinderDied();
                 } break;
+
+                case MSG_REQUEST_CUSTOM_PRINTER_ICON: {
+                    PrinterId printerId = (PrinterId) message.obj;
+                    handleRequestCustomPrinterIcon(printerId);
+                } break;
             }
         }
     }
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
new file mode 100644
index 0000000..403b65c
--- /dev/null
+++ b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
@@ -0,0 +1,222 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.media.session.MediaSession;
+import android.os.Build;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.service.notification.StatusBarNotification;
+import android.telecom.TelecomManager;
+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.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NotificationComparatorTest {
+    @Mock Context mContext;
+    @Mock TelecomManager mTm;
+    @Mock RankingHandler handler;
+    @Mock PackageManager mPm;
+
+    private final String callPkg = "com.android.server.notification";
+    private final int callUid = 10;
+    private String smsPkg;
+    private final int smsUid = 11;
+    private final String pkg2 = "pkg2";
+    private final int uid2 = 1111111;
+
+    private NotificationRecord mRecordMinCall;
+    private NotificationRecord mRecordHighCall;
+    private NotificationRecord mRecordDefaultMedia;
+    private NotificationRecord mRecordEmail;
+    private NotificationRecord mRecordInlineReply;
+    private NotificationRecord mRecordSms;
+    private NotificationRecord mRecordStarredContact;
+    private NotificationRecord mRecordContact;
+    private NotificationRecord mRecordUrgent;
+    private NotificationRecord mRecordCheater;
+
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        int userId = UserHandle.myUserId();
+
+        when(mContext.getResources()).thenReturn(
+                InstrumentationRegistry.getTargetContext().getResources());
+        when(mContext.getContentResolver()).thenReturn(
+                InstrumentationRegistry.getTargetContext().getContentResolver());
+        when(mContext.getPackageManager()).thenReturn(mPm);
+        when(mContext.getSystemService(eq(Context.TELECOM_SERVICE))).thenReturn(mTm);
+        when(mTm.getDefaultDialerPackage()).thenReturn(callPkg);
+        final ApplicationInfo legacy = new ApplicationInfo();
+        legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
+        try {
+            when(mPm.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())).thenReturn(legacy);
+            when(mContext.getApplicationInfo()).thenReturn(legacy);
+        } catch (PackageManager.NameNotFoundException e) {
+            // let's hope not
+        }
+
+        smsPkg = Settings.Secure.getString(mContext.getContentResolver(),
+                Settings.Secure.SMS_DEFAULT_APPLICATION);
+
+        Notification n1 = new Notification.Builder(mContext)
+                .setCategory(Notification.CATEGORY_CALL)
+                .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
+                .build();
+        mRecordMinCall = new NotificationRecord(mContext, new StatusBarNotification(callPkg,
+                callPkg, getDefaultChannel(), 1, "minCall", callUid, callUid, n1,
+                new UserHandle(userId), "", 2000));
+        mRecordMinCall.setUserImportance(NotificationManager.IMPORTANCE_MIN);
+
+        Notification n2 = new Notification.Builder(mContext)
+                .setCategory(Notification.CATEGORY_CALL)
+                .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
+                .build();
+        mRecordHighCall = new NotificationRecord(mContext, new StatusBarNotification(callPkg,
+                callPkg, getDefaultChannel(), 1, "highcall", callUid, callUid, n2,
+                new UserHandle(userId), "", 1999));
+        mRecordHighCall.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
+
+        Notification n3 = new Notification.Builder(mContext)
+                .setStyle(new Notification.MediaStyle()
+                        .setMediaSession(new MediaSession.Token(null)))
+                .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
+                .build();
+        mRecordDefaultMedia = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
+                pkg2, getDefaultChannel(), 1, "media", uid2, uid2, n3, new UserHandle(userId),
+                "", 1499));
+        mRecordDefaultMedia.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
+
+        Notification n4 = new Notification.Builder(mContext)
+                .setStyle(new Notification.MessagingStyle("sender!")).build();
+        mRecordInlineReply = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
+                pkg2, getDefaultChannel(), 1, "inlinereply", uid2, uid2, n4, new UserHandle(userId),
+                "", 1599));
+        mRecordInlineReply.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
+        mRecordInlineReply.setPackagePriority(Notification.PRIORITY_MAX);
+
+        Notification n5 = new Notification.Builder(mContext)
+                .setCategory(Notification.CATEGORY_MESSAGE).build();
+        mRecordSms = new NotificationRecord(mContext, new StatusBarNotification(smsPkg,
+                smsPkg, getDefaultChannel(), 1, "sms", smsUid, smsUid, n5, new UserHandle(userId),
+                "", 1299));
+        mRecordSms.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
+
+        Notification n6 = new Notification.Builder(mContext).build();
+        mRecordStarredContact = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
+                pkg2, getDefaultChannel(), 1, "starred", uid2, uid2, n6, new UserHandle(userId),
+                "", 1259));
+        mRecordStarredContact.setContactAffinity(ValidateNotificationPeople.STARRED_CONTACT);
+        mRecordStarredContact.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
+
+        Notification n7 = new Notification.Builder(mContext).build();
+        mRecordContact = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
+                pkg2, getDefaultChannel(), 1, "contact", uid2, uid2, n7, new UserHandle(userId),
+                "", 1259));
+        mRecordContact.setContactAffinity(ValidateNotificationPeople.VALID_CONTACT);
+        mRecordContact.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
+
+        Notification n8 = new Notification.Builder(mContext).build();
+        mRecordUrgent = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
+                pkg2, getDefaultChannel(), 1, "urgent", uid2, uid2, n8, new UserHandle(userId),
+                "", 1258));
+        mRecordUrgent.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
+
+        Notification n9 = new Notification.Builder(mContext)
+                .setCategory(Notification.CATEGORY_MESSAGE)
+                .setFlag(Notification.FLAG_ONGOING_EVENT
+                        |Notification.FLAG_FOREGROUND_SERVICE, true)
+                .build();
+        mRecordCheater = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
+                pkg2, getDefaultChannel(), 1, "cheater", uid2, uid2, n9, new UserHandle(userId),
+                "", 9258));
+        mRecordCheater.setUserImportance(NotificationManager.IMPORTANCE_LOW);
+
+        Notification n10 = new Notification.Builder(mContext)
+                .setStyle(new Notification.InboxStyle().setSummaryText("message!")).build();
+        mRecordEmail = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
+                pkg2, getDefaultChannel(), 1, "email", uid2, uid2, n10, new UserHandle(userId),
+                "", 1599));
+        mRecordEmail.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
+    }
+
+    @Test
+    public void testOrdering() throws Exception {
+        final List<NotificationRecord> expected = new ArrayList<>();
+        expected.add(mRecordHighCall);
+        expected.add(mRecordDefaultMedia);
+        expected.add(mRecordStarredContact);
+        expected.add(mRecordContact);
+        expected.add(mRecordInlineReply);
+        expected.add(mRecordSms);
+        expected.add(mRecordEmail);
+        expected.add(mRecordUrgent);
+        expected.add(mRecordCheater);
+        expected.add(mRecordMinCall);
+
+        List<NotificationRecord> actual = new ArrayList<>();
+        actual.addAll(expected);
+        Collections.shuffle(actual);
+
+        Collections.sort(actual, new NotificationComparator(mContext));
+
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testMessaging() throws Exception {
+        NotificationComparator comp = new NotificationComparator(mContext);
+        assertTrue(comp.isImportantMessaging(mRecordStarredContact));
+        assertTrue(comp.isImportantMessaging(mRecordContact));
+        assertTrue(comp.isImportantMessaging(mRecordInlineReply));
+        assertTrue(comp.isImportantMessaging(mRecordSms));
+        assertFalse(comp.isImportantMessaging(mRecordEmail));
+        assertFalse(comp.isImportantMessaging(mRecordCheater));
+    }
+
+    private NotificationChannel getDefaultChannel() {
+        return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name",
+                NotificationManager.IMPORTANCE_LOW);
+    }
+}
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index e4a355f..80c4cce 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -57,8 +57,6 @@
         when(mockPackageManager.getApplicationInfo(any(), anyInt(), anyInt()))
                 .thenReturn(applicationInfo);
         mNotificationManagerService.setPackageManager(mockPackageManager);
-
-        mNotificationManagerService.setRankingHelper(mock(RankingHelper.class));
         mNotificationManagerService.setHandler(new Handler(context.getMainLooper()));
 
         // Tests call directly into the Binder.
@@ -69,6 +67,7 @@
     public void testCreateNotificationChannel_SuccessCallsListener() throws Exception {
         final NotificationChannel channel =
                 new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
+        mNotificationManagerService.setRankingHelper(mock(RankingHelper.class));
         final CountDownLatch latch = new CountDownLatch(1);
         mBinderService.createNotificationChannel("test_pkg", channel,
                 new IOnNotificationChannelCreatedListener.Stub() {
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
index a7d2c04..fc94271f 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
@@ -59,7 +59,7 @@
     @Mock PackageManager mPm;
 
     private final String pkg = "com.android.server.notification";
-    private final int uid = 0;
+    private final int uid = 9583;
     private final String pkg2 = "pkg2";
     private final int uid2 = 1111111;
     private final int id1 = 1;
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 16d0a75..e6afe76 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -375,7 +375,7 @@
         final NotificationChannel channel2 =
             new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
 
-        mHelper.updateNotificationChannelFromRanker(pkg, uid, channel2);
+        mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
 
         // no fields should be changed
         assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId()));
@@ -396,7 +396,7 @@
             new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
         channel2.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
 
-        mHelper.updateNotificationChannelFromRanker(pkg, uid, channel2);
+        mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
 
         // no fields should be changed
         assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId()));
@@ -418,7 +418,7 @@
         channel2.enableVibration(true);
         channel2.setVibrationPattern(new long[] {100});
 
-        mHelper.updateNotificationChannelFromRanker(pkg, uid, channel2);
+        mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
 
         // no fields should be changed
         assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId()));
@@ -439,7 +439,7 @@
             new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
         channel2.setLights(true);
 
-        mHelper.updateNotificationChannelFromRanker(pkg, uid, channel2);
+        mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
 
         // no fields should be changed
         assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId()));
@@ -460,7 +460,7 @@
             new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
         channel2.setBypassDnd(false);
 
-        mHelper.updateNotificationChannelFromRanker(pkg, uid, channel2);
+        mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
 
         // no fields should be changed
         assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId()));
@@ -481,7 +481,7 @@
             new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
         channel2.setSound(new Uri.Builder().scheme("test2").build());
 
-        mHelper.updateNotificationChannelFromRanker(pkg, uid, channel2);
+        mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
 
         // no fields should be changed
         assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId()));
diff --git a/services/tests/servicestests/src/android/net/util/BlockingSocketReaderTest.java b/services/tests/servicestests/src/android/net/util/BlockingSocketReaderTest.java
new file mode 100644
index 0000000..e03350f
--- /dev/null
+++ b/services/tests/servicestests/src/android/net/util/BlockingSocketReaderTest.java
@@ -0,0 +1,148 @@
+/*
+ * 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 static android.system.OsConstants.*;
+
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructTimeval;
+
+import libcore.io.IoBridge;
+
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketException;
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for BlockingSocketReader.
+ *
+ * @hide
+ */
+public class BlockingSocketReaderTest extends TestCase {
+    static final InetAddress LOOPBACK6 = Inet6Address.getLoopbackAddress();
+    static final StructTimeval TIMEO = StructTimeval.fromMillis(500);
+
+    protected CountDownLatch mLatch;
+    protected FileDescriptor mLocalSocket;
+    protected InetSocketAddress mLocalSockName;
+    protected byte[] mLastRecvBuf;
+    protected boolean mExited;
+    protected BlockingSocketReader mReceiver;
+
+    @Override
+    public void setUp() {
+        resetLatch();
+        mLocalSocket = null;
+        mLocalSockName = null;
+        mLastRecvBuf = null;
+        mExited = false;
+
+        mReceiver = new BlockingSocketReader() {
+            @Override
+            protected FileDescriptor createSocket() {
+                FileDescriptor s = null;
+                try {
+                    s = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+                    Os.bind(s, LOOPBACK6, 0);
+                    mLocalSockName = (InetSocketAddress) Os.getsockname(s);
+                    Os.setsockoptTimeval(s, SOL_SOCKET, SO_SNDTIMEO, TIMEO);
+                } catch (ErrnoException|SocketException e) {
+                    closeSocket(s);
+                    fail();
+                    return null;
+                }
+
+                mLocalSocket = s;
+                return s;
+            }
+
+            @Override
+            protected void handlePacket(byte[] recvbuf, int length) {
+                mLastRecvBuf = Arrays.copyOf(recvbuf, length);
+                mLatch.countDown();
+            }
+
+            @Override
+            protected void onExit() {
+                mExited = true;
+                mLatch.countDown();
+            }
+        };
+    }
+
+    @Override
+    public void tearDown() {
+        if (mReceiver != null) mReceiver.stop();
+        mReceiver = null;
+    }
+
+    void resetLatch() { mLatch = new CountDownLatch(1); }
+
+    void waitForActivity() throws Exception {
+        assertTrue(mLatch.await(500, TimeUnit.MILLISECONDS));
+        resetLatch();
+    }
+
+    void sendPacket(byte[] contents) throws Exception {
+        final DatagramSocket sender = new DatagramSocket();
+        sender.connect(mLocalSockName);
+        sender.send(new DatagramPacket(contents, contents.length));
+        sender.close();
+    }
+
+    public void testBasicWorking() throws Exception {
+        assertTrue(mReceiver.start());
+        assertTrue(mLocalSockName != null);
+        assertEquals(LOOPBACK6, mLocalSockName.getAddress());
+        assertTrue(0 < mLocalSockName.getPort());
+        assertTrue(mLocalSocket != null);
+        assertFalse(mExited);
+
+        final byte[] one = "one 1".getBytes("UTF-8");
+        sendPacket(one);
+        waitForActivity();
+        assertEquals(1, mReceiver.numPacketsReceived());
+        assertTrue(Arrays.equals(one, mLastRecvBuf));
+        assertFalse(mExited);
+
+        final byte[] two = "two 2".getBytes("UTF-8");
+        sendPacket(two);
+        waitForActivity();
+        assertEquals(2, mReceiver.numPacketsReceived());
+        assertTrue(Arrays.equals(two, mLastRecvBuf));
+        assertFalse(mExited);
+
+        mReceiver.stop();
+        waitForActivity();
+        assertEquals(2, mReceiver.numPacketsReceived());
+        assertTrue(Arrays.equals(two, mLastRecvBuf));
+        assertTrue(mExited);
+    }
+}
diff --git a/services/tests/servicestests/src/android/net/util/ConnectivityPacketSummaryTest.java b/services/tests/servicestests/src/android/net/util/ConnectivityPacketSummaryTest.java
new file mode 100644
index 0000000..766e5c0
--- /dev/null
+++ b/services/tests/servicestests/src/android/net/util/ConnectivityPacketSummaryTest.java
@@ -0,0 +1,377 @@
+/*
+ * 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 static android.net.util.NetworkConstants.*;
+
+import libcore.util.HexEncoding;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for ConnectivityPacketSummary.
+ *
+ * @hide
+ */
+public class ConnectivityPacketSummaryTest extends TestCase {
+    private static final byte[] MYHWADDR = {
+        asByte(0x80), asByte(0x7a), asByte(0xbf), asByte(0x6f), asByte(0x48), asByte(0xf3)
+    };
+
+    private String getSummary(String hexBytes) {
+        hexBytes = hexBytes.replaceAll("\\s+", "");
+        final byte[] bytes = HexEncoding.decode(hexBytes.toCharArray(), false);
+        return ConnectivityPacketSummary.summarize(MYHWADDR, bytes);
+    }
+
+    public void testParseICMPv6DADProbe() {
+        final String packet =
+                // Ethernet
+                "3333FF6F48F3 807ABF6F48F3 86DD" +
+                // IPv6
+                "600000000018 3A FF" +
+                "00000000000000000000000000000000" +
+                "FF0200000000000000000001FF6F48F3" +
+                // ICMPv6
+                "87 00 A8E7" +
+                "00000000" +
+                "FE80000000000000827ABFFFFE6F48F3";
+
+        final String expected =
+                "TX 80:7a:bf:6f:48:f3 > 33:33:ff:6f:48:f3 ipv6" +
+                " :: > ff02::1:ff6f:48f3 icmp6" +
+                " ns fe80::827a:bfff:fe6f:48f3";
+
+        assertEquals(expected, getSummary(packet));
+    }
+
+    public void testParseICMPv6RS() {
+        final String packet =
+                // Ethernet
+                "333300000002 807ABF6F48F3 86DD" +
+                // IPv6
+                "600000000010 3A FF" +
+                "FE80000000000000827ABFFFFE6F48F3" +
+                "FF020000000000000000000000000002" +
+                // ICMPv6 RS
+                "85 00 6973" +
+                "00000000" +
+                "01 01 807ABF6F48F3";
+
+        final String expected =
+                "TX 80:7a:bf:6f:48:f3 > 33:33:00:00:00:02 ipv6" +
+                " fe80::827a:bfff:fe6f:48f3 > ff02::2 icmp6" +
+                " rs slla 80:7a:bf:6f:48:f3";
+
+        assertEquals(expected, getSummary(packet));
+    }
+
+    public void testParseICMPv6RA() {
+        final String packet =
+                // Ethernet
+                "807ABF6F48F3 100E7E263FC1 86DD" +
+                // IPv6
+                "600000000068 3A FF" +
+                "FE80000000000000FA000004FD000001" +
+                "FE80000000000000827ABFFFFE6F48F3" +
+                // ICMPv6 RA
+                "86 00 8141" +
+                "40 00 0E10" +
+                "00000000" +
+                "00000000" +
+                "01 01 00005E000265" +
+                "05 01 0000000005DC" +
+                "19 05 000000000E10" +
+                "      20014860486000000000000000008844" +
+                "      20014860486000000000000000008888" +
+                "03 04 40 C0" +
+                "      00278D00" +
+                "      00093A80" +
+                "      00000000" +
+                "      2401FA000004FD000000000000000000";
+
+        final String expected =
+                "RX 10:0e:7e:26:3f:c1 > 80:7a:bf:6f:48:f3 ipv6" +
+                " fe80::fa00:4:fd00:1 > fe80::827a:bfff:fe6f:48f3 icmp6" +
+                " ra slla 00:00:5e:00:02:65 mtu 1500";
+
+        assertEquals(expected, getSummary(packet));
+    }
+
+    public void testParseICMPv6NS() {
+        final String packet =
+                // Ethernet
+                  "807ABF6F48F3 100E7E263FC1 86DD" +
+                  // IPv6
+                  "6C0000000020 3A FF" +
+                  "FE80000000000000FA000004FD000001" +
+                  "FF0200000000000000000001FF01C146" +
+                  // ICMPv6 NS
+                  "87 00 8AD4" +
+                  "00000000" +
+                  "2401FA000004FD0015EA6A5C7B01C146" +
+                  "01 01 00005E000265";
+
+        final String expected =
+                "RX 10:0e:7e:26:3f:c1 > 80:7a:bf:6f:48:f3 ipv6" +
+                " fe80::fa00:4:fd00:1 > ff02::1:ff01:c146 icmp6" +
+                " ns 2401:fa00:4:fd00:15ea:6a5c:7b01:c146 slla 00:00:5e:00:02:65";
+
+        assertEquals(expected, getSummary(packet));
+    }
+
+    public void testParseICMPv6NA() {
+        final String packet =
+                // Ethernet
+                "00005E000265 807ABF6F48F3 86DD" +
+                "600000000020 3A FF" +
+                "2401FA000004FD0015EA6A5C7B01C146" +
+                "FE80000000000000FA000004FD000001" +
+                "88 00 E8126" +
+                "0000000" +
+                "2401FA000004FD0015EA6A5C7B01C146" +
+                "02 01 807ABF6F48F3";
+
+        final String expected =
+                "TX 80:7a:bf:6f:48:f3 > 00:00:5e:00:02:65 ipv6" +
+                " 2401:fa00:4:fd00:15ea:6a5c:7b01:c146 > fe80::fa00:4:fd00:1 icmp6" +
+                " na 2401:fa00:4:fd00:15ea:6a5c:7b01:c146 tlla 80:7a:bf:6f:48:f3";
+
+        assertEquals(expected, getSummary(packet));
+    }
+
+    public void testParseARPRequest() {
+        final String packet =
+                // Ethernet
+                  "FFFFFFFFFFFF 807ABF6F48F3 0806" +
+                  // ARP
+                  "0001 0800 06 04" +
+                  // Request
+                  "0001" +
+                  "807ABF6F48F3 64706ADB" +
+                  "000000000000 64706FFD";
+
+        final String expected =
+                "TX 80:7a:bf:6f:48:f3 > ff:ff:ff:ff:ff:ff arp" +
+                " who-has 100.112.111.253";
+
+        assertEquals(expected, getSummary(packet));
+    }
+
+    public void testParseARPReply() {
+        final String packet =
+                // Ethernet
+                  "807ABF6F48F3 288A1CA8DFC1 0806" +
+                  // ARP
+                  "0001 0800 06 04" +
+                  // Reply
+                  "0002" +
+                  "288A1CA8DFC1 64706FFD"+
+                  "807ABF6F48F3 64706ADB" +
+                  // Ethernet padding to packet min size.
+                  "0000000000000000000000000000";
+
+        final String expected =
+                "RX 28:8a:1c:a8:df:c1 > 80:7a:bf:6f:48:f3 arp" +
+                " reply 100.112.111.253 28:8a:1c:a8:df:c1";
+
+        assertEquals(expected, getSummary(packet));
+    }
+
+    public void testParseDHCPv4Discover() {
+        final String packet =
+                // Ethernet
+                "FFFFFFFFFFFF 807ABF6F48F3 0800" +
+                // IPv4
+                "451001580000400040113986" +
+                "00000000" +
+                "FFFFFFFF" +
+                // UDP
+                "0044 0043" +
+                "0144 5559" +
+                // DHCPv4
+                "01 01 06 00" +
+                "79F7ACA4" +
+                "0000 0000" +
+                "00000000" +
+                "00000000" +
+                "00000000" +
+                "00000000" +
+                "807ABF6F48F300000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "63 82 53 63" +
+                "35 01 01" +
+                "3D 07 01807ABF6F48F3" +
+                "39 02 05DC" +
+                "3C 12 616E64726F69642D646863702D372E312E32" +
+                "0C 18 616E64726F69642D36623030366333313333393835343139" +
+                "37 0A 01 03 06 0F 1A 1C 33 3A 3B 2B" +
+                "FF" +
+                "00";
+
+        final String expectedPrefix =
+                "TX 80:7a:bf:6f:48:f3 > ff:ff:ff:ff:ff:ff ipv4" +
+                " 0.0.0.0 > 255.255.255.255 udp" +
+                " 68 > 67 dhcp4" +
+                " 80:7a:bf:6f:48:f3 DISCOVER";
+
+        assertTrue(getSummary(packet).startsWith(expectedPrefix));
+    }
+
+    public void testParseDHCPv4Offer() {
+        final String packet =
+                // Ethernet
+                "807ABF6F48F3 288A1CA8DFC1 0800" +
+                // IPv4
+                "4500013D4D2C0000401188CB" +
+                "64706FFD" +
+                "64706ADB" +
+                // UDP
+                "0043 0044" +
+                "0129 371D" +
+                // DHCPv4
+                "02 01 06 01" +
+                "79F7ACA4" +
+                "0000 0000" +
+                "00000000" +
+                "64706ADB" +
+                "00000000" +
+                "00000000" +
+                "807ABF6F48F300000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "63 82 53 63" +
+                "35 01 02" +
+                "36 04 AC188A0B" +
+                "33 04 00000708" +
+                "01 04 FFFFF000" +
+                "03 04 64706FFE" +
+                "06 08 08080808" +
+                "      08080404" +
+                "FF0001076165313A363636FF";
+
+        final String expectedPrefix =
+                "RX 28:8a:1c:a8:df:c1 > 80:7a:bf:6f:48:f3 ipv4" +
+                " 100.112.111.253 > 100.112.106.219 udp" +
+                " 67 > 68 dhcp4" +
+                " 80:7a:bf:6f:48:f3 OFFER";
+
+        assertTrue(getSummary(packet).startsWith(expectedPrefix));
+    }
+
+    public void testParseDHCPv4Request() {
+        final String packet =
+                // Ethernet
+                "FFFFFFFFFFFF 807ABF6F48F3 0800" +
+                // IPv4
+                "45100164000040004011397A" +
+                "00000000" +
+                "FFFFFFFF" +
+                // UDP
+                "0044 0043" +
+                "0150 E5C7" +
+                // DHCPv4
+                "01 01 06 00" +
+                "79F7ACA4" +
+                "0001 0000" +
+                "00000000" +
+                "00000000" +
+                "00000000" +
+                "00000000" +
+                "807ABF6F48F300000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "63 82 53 63" +
+                "35 01 03" +
+                "3D 07 01807ABF6F48F3" +
+                "32 04 64706ADB" +
+                "36 04 AC188A0B" +
+                "39 02 05DC" +
+                "3C 12 616E64726F69642D646863702D372E312E32" +
+                "0C 18 616E64726F69642D36623030366333313333393835343139" +
+                "37 0A 01 03 06 0F 1A 1C 33 3A 3B 2B" +
+                "FF" +
+                "00";
+
+        final String expectedPrefix =
+                "TX 80:7a:bf:6f:48:f3 > ff:ff:ff:ff:ff:ff ipv4" +
+                " 0.0.0.0 > 255.255.255.255 udp" +
+                " 68 > 67 dhcp4" +
+                " 80:7a:bf:6f:48:f3 REQUEST";
+
+        assertTrue(getSummary(packet).startsWith(expectedPrefix));
+    }
+
+    public void testParseDHCPv4Ack() {
+        final String packet =
+                // Ethernet
+                "807ABF6F48F3 288A1CA8DFC1 0800" +
+                // IPv4
+                "4500013D4D3B0000401188BC" +
+                "64706FFD" +
+                "64706ADB" +
+                // UDP
+                "0043 0044" +
+                "0129 341C" +
+                // DHCPv4
+                "02 01 06 01" +
+                "79F7ACA4" +
+                "0001 0000" +
+                "00000000" +
+                "64706ADB" +
+                "00000000" +
+                "00000000" +
+                "807ABF6F48F300000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "63 82 53 63" +
+                "35 01 05" +
+                "36 04 AC188A0B" +
+                "33 04 00000708" +
+                "01 04 FFFFF000" +
+                "03 04 64706FFE" +
+                "06 08 08080808" +
+                "      08080404" +
+                "FF0001076165313A363636FF";
+
+        final String expectedPrefix =
+                "RX 28:8a:1c:a8:df:c1 > 80:7a:bf:6f:48:f3 ipv4" +
+                " 100.112.111.253 > 100.112.106.219 udp" +
+                " 67 > 68 dhcp4" +
+                " 80:7a:bf:6f:48:f3 ACK";
+
+        assertTrue(getSummary(packet).startsWith(expectedPrefix));
+    }
+}
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 0c00886..48c9853 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -49,6 +49,7 @@
 import com.android.internal.R;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.pm.UserRestrictionsUtils;
 
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
@@ -1190,6 +1191,22 @@
         assertTrue(dpm.setDeviceOwner(admin1, "owner-name",
                 UserHandle.USER_SYSTEM));
 
+        // Check that the user restrictions that are enabled by default are set. Then unset them.
+        String[] defaultRestrictions = UserRestrictionsUtils
+                        .getDefaultEnabledForDeviceOwner().toArray(new String[0]);
+        DpmTestUtils.assertRestrictions(
+                DpmTestUtils.newRestrictions(defaultRestrictions),
+                dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
+        );
+        DpmTestUtils.assertRestrictions(
+                DpmTestUtils.newRestrictions(defaultRestrictions),
+                dpm.getUserRestrictions(admin1)
+        );
+
+        for (String restriction : defaultRestrictions) {
+            dpm.clearUserRestriction(admin1, restriction);
+        }
+
         DpmTestUtils.assertRestrictions(
                 DpmTestUtils.newRestrictions(),
                 dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
@@ -2188,7 +2205,7 @@
         assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                 DevicePolicyManager.CODE_OK);
         assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
-                DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE);
+                DevicePolicyManager.CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER);
         assertCheckProvisioningPreCondition(
                 DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
                 DevicePolicyManager.CODE_OK);
@@ -2226,7 +2243,7 @@
         assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                 DevicePolicyManager.CODE_OK);
         assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
-                DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE);
+                DevicePolicyManager.CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER);
         assertCheckProvisioningPreCondition(
                 DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
                 DevicePolicyManager.CODE_OK);
@@ -2368,7 +2385,9 @@
         when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
                 .thenReturn(true);
         when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
-        when(mContext.userManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER))
+        when(mContext.userManager.hasUserRestriction(
+                UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
+                UserHandle.of(DpmMockContext.CALLER_USER_HANDLE)))
                 .thenReturn(true);
         when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
                 false /* we can't remove a managed profile */)).thenReturn(false);
@@ -2664,8 +2683,26 @@
         final int ANOTHER_USER_ID = 36;
         mContext.addUser(ANOTHER_USER_ID, 0);
 
+        // Since the managed profile is not affiliated, they should not be allowed to talk to each
+        // other.
+        targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
+        MoreAsserts.assertEmpty(targetUsers);
+
+        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
+        targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
+        MoreAsserts.assertEmpty(targetUsers);
+
+        // Setting affiliation ids
+        final List<String> userAffiliationIds = Arrays.asList("some.affiliation-id");
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        dpm.setAffiliationIds(admin1, userAffiliationIds);
+
+        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
+        dpm.setAffiliationIds(admin1, userAffiliationIds);
+
         // Calling from device owner admin, the result list should just contain the managed
         // profile user id.
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
         MoreAsserts.assertContentsInAnyOrder(targetUsers, UserHandle.of(MANAGED_PROFILE_USER_ID));
 
@@ -2674,6 +2711,18 @@
         mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
         targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
         MoreAsserts.assertContentsInAnyOrder(targetUsers, UserHandle.SYSTEM);
+
+        // Changing affiliation ids in one
+        dpm.setAffiliationIds(admin1, Arrays.asList("some-different-affiliation-id"));
+
+        // Since the managed profile is not affiliated any more, they should not be allowed to talk
+        // to each other.
+        targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
+        MoreAsserts.assertEmpty(targetUsers);
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
+        MoreAsserts.assertEmpty(targetUsers);
     }
 
     public void testGetBindDeviceAdminTargetUsers_differentPackage() throws Exception {
@@ -2688,8 +2737,16 @@
                 new ComponentName("another.package", "whatever.class");
         addManagedProfile(adminDifferentPackage, MANAGED_PROFILE_ADMIN_UID, admin2);
 
+        // Setting affiliation ids
+        final List<String> userAffiliationIds = Arrays.asList("some-affiliation-id");
+        dpm.setAffiliationIds(admin1, userAffiliationIds);
+
+        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
+        dpm.setAffiliationIds(adminDifferentPackage, userAffiliationIds);
+
         // Calling from device owner admin, we should get zero bind device admin target users as
         // their packages are different.
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         List<UserHandle> targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
         MoreAsserts.assertEmpty(targetUsers);
 
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 99af9e8..6bc4c19 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -46,6 +46,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ILauncherApps;
@@ -70,10 +71,12 @@
 import android.os.Looper;
 import android.os.PersistableBundle;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.test.InstrumentationTestCase;
 import android.test.mock.MockContext;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Pair;
 
@@ -123,6 +126,7 @@
     protected static final String[] EMPTY_STRINGS = new String[0]; // Just for readability.
 
     protected static final String MAIN_ACTIVITY_CLASS = "MainActivity";
+    protected static final String PIN_CONFIRM_ACTIVITY_CLASS = "PinConfirmActivity";
 
     // public for mockito
     public class BaseContext extends MockContext {
@@ -161,6 +165,11 @@
         public void unregisterReceiver(BroadcastReceiver receiver) {
             // ignore.
         }
+
+        @Override
+        public void startActivityAsUser(Intent intent, UserHandle user) {
+            // ignore, use spy to intercept it.
+        }
     }
 
     /** Context used in the client side */
@@ -201,6 +210,10 @@
         public XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) {
             return BaseShortcutManagerTest.this.injectXmlMetaData(activityInfo, key);
         }
+
+        public void sendIntentSender(IntentSender intent) {
+            // Placeholder for spying.
+        }
     }
 
     /** ShortcutService with injection override methods. */
@@ -304,6 +317,15 @@
         }
 
         @Override
+        ComponentName getDefaultLauncher(@UserIdInt int userId) {
+            final ComponentName activity = mDefaultLauncher.get(userId);
+            if (activity != null) {
+                return activity;
+            }
+            return super.getDefaultLauncher(userId);
+        }
+
+        @Override
         PackageInfo injectPackageInfoWithUninstalled(String packageName, @UserIdInt int userId,
                 boolean getSignatures) {
             return getInjectedPackageInfo(packageName, userId, getSignatures);
@@ -375,6 +397,12 @@
         }
 
         @Override
+        ComponentName injectGetPinConfirmationActivity(@NonNull String launcherPackageName,
+                int launcherUserId) {
+            return mPinConfirmActivityFetcher.apply(launcherPackageName, launcherUserId);
+        }
+
+        @Override
         boolean injectIsActivityEnabledAndExported(ComponentName activity, @UserIdInt int userId) {
             assertNotNull(activity);
             return mEnabledActivityChecker.test(activity, userId);
@@ -413,6 +441,11 @@
         }
 
         @Override
+        void injectSendIntentSender(IntentSender intent) {
+            mContext.sendIntentSender(intent);
+        }
+
+        @Override
         void wtf(String message, Throwable th) {
             // During tests, WTF is fatal.
             fail(message + "  exception: " + th + "\n" + Log.getStackTraceString(th));
@@ -583,7 +616,7 @@
 
     protected static final UserInfo USER_INFO_0 = withProfileGroupId(
             new UserInfo(USER_0, "user0",
-                    UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED), 10);
+                    UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED), 0);
 
     protected static final UserInfo USER_INFO_10 =
             new UserInfo(USER_10, "user10", UserInfo.FLAG_INITIALIZED);
@@ -593,19 +626,24 @@
 
     protected static final UserInfo USER_INFO_P0 = withProfileGroupId(
             new UserInfo(USER_P0, "userP0",
-                    UserInfo.FLAG_MANAGED_PROFILE), 10);
+                    UserInfo.FLAG_MANAGED_PROFILE), 0);
 
     protected BiPredicate<String, Integer> mDefaultLauncherChecker =
             (callingPackage, userId) ->
             LAUNCHER_1.equals(callingPackage) || LAUNCHER_2.equals(callingPackage)
             || LAUNCHER_3.equals(callingPackage) || LAUNCHER_4.equals(callingPackage);
 
+    private final Map<Integer, ComponentName> mDefaultLauncher = new ArrayMap<>();
+
     protected BiPredicate<ComponentName, Integer> mMainActivityChecker =
             (activity, userId) -> true;
 
     protected BiFunction<String, Integer, ComponentName> mMainActivityFetcher =
             (packageName, userId) -> new ComponentName(packageName, MAIN_ACTIVITY_CLASS);
 
+    protected BiFunction<String, Integer, ComponentName> mPinConfirmActivityFetcher =
+            (packageName, userId) -> new ComponentName(packageName, PIN_CONFIRM_ACTIVITY_CLASS);
+
     protected BiPredicate<ComponentName, Integer> mEnabledActivityChecker
             = (activity, userId) -> true; // all activities are enabled.
 
@@ -722,6 +760,19 @@
                     return b(mRunningUsers.get(userId)) && b(mUnlockedUsers.get(userId));
                 }));
 
+        when(mMockUserManager.getProfileParent(anyInt()))
+                .thenAnswer(new AnswerWithSystemCheck<>(inv -> {
+                    final int userId = (Integer) inv.getArguments()[0];
+                    final UserInfo ui = mUserInfos.get(userId);
+                    assertNotNull(ui);
+                    if (ui.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
+                        return null;
+                    }
+                    final UserInfo parent = mUserInfos.get(ui.profileGroupId);
+                    assertNotNull(parent);
+                    return parent;
+                }));
+
         when(mMockActivityManagerInternal.getUidProcessState(anyInt())).thenReturn(
                 ActivityManager.PROCESS_STATE_CACHED_EMPTY);
 
@@ -1098,10 +1149,31 @@
         return mInjectedClientPackage;
     }
 
+    /**
+     * This controls {@link ShortcutService#hasShortcutHostPermission(String, int)}, but
+     * not {@link ShortcutService#getDefaultLauncher(int)}.  To control the later, use
+     * {@link #setDefaultLauncher(int, ComponentName)}.
+     */
     protected void setDefaultLauncherChecker(BiPredicate<String, Integer> p) {
         mDefaultLauncherChecker = p;
     }
 
+    /**
+     * Set the default launcher.  This will update {@link #mDefaultLauncherChecker} set by
+     * {@link #setDefaultLauncherChecker} too.
+     */
+    protected void setDefaultLauncher(int userId, ComponentName launcherActivity) {
+        mDefaultLauncher.put(userId, launcherActivity);
+
+        final BiPredicate<String, Integer> oldChecker = mDefaultLauncherChecker;
+        mDefaultLauncherChecker = (checkPackageName, checkUserId) -> {
+            if ((checkUserId == userId) && (launcherActivity !=  null)) {
+                return launcherActivity.getPackageName().equals(checkPackageName);
+            }
+            return oldChecker.test(checkPackageName, checkUserId);
+        };
+    }
+
     protected void runWithCaller(String packageName, int userId, Runnable r) {
         final String previousPackage = mInjectedClientPackage;
         final int previousUserId = UserHandle.getUserId(mInjectedCallingUid);
@@ -1218,6 +1290,13 @@
     }
 
     /**
+     * Make a shortcut with an ID only.
+     */
+    protected ShortcutInfo makeShortcutIdOnly(String id) {
+        return new ShortcutInfo.Builder(mClientContext, id).build();
+    }
+
+    /**
      * Make a shortcut with an ID.
      */
     protected ShortcutInfo makeShortcut(String id) {
@@ -1226,12 +1305,19 @@
                 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
     }
 
+    @Deprecated // Title was renamed to short label.
     protected ShortcutInfo makeShortcutWithTitle(String id, String title) {
         return makeShortcut(
                 id, title, /* activity =*/ null, /* icon =*/ null,
                 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
     }
 
+    protected ShortcutInfo makeShortcutWithShortLabel(String id, String shortLabel) {
+        return makeShortcut(
+                id, shortLabel, /* activity =*/ null, /* icon =*/ null,
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+    }
+
     /**
      * Make a shortcut with an ID and timestamp.
      */
@@ -1624,6 +1710,13 @@
         return getLauncherShortcuts(launcher, userId, ShortcutQuery.FLAG_GET_PINNED);
     }
 
+    protected List<ShortcutInfo> getShortcutAsLauncher(int targetUserId) {
+        final ShortcutQuery q = new ShortcutQuery();
+        q.setQueryFlags(ShortcutQuery.FLAG_MATCH_DYNAMIC | ShortcutQuery.FLAG_MATCH_DYNAMIC
+                | ShortcutQuery.FLAG_MATCH_PINNED);
+        return mLauncherApps.getShortcuts(q, UserHandle.of(targetUserId));
+    }
+
     protected ShortcutInfo getShortcutInfoAsLauncher(String packageName, String shortcutId,
             int userId) {
         final List<ShortcutInfo> infoList =
@@ -1897,7 +1990,8 @@
     public static List<ShortcutInfo> assertAllHaveIcon(
             List<ShortcutInfo> actualShortcuts) {
         for (ShortcutInfo s : actualShortcuts) {
-            assertTrue("ID " + s.getId() + " has no icon ", s.hasIconFile() || s.hasIconResource());
+            assertTrue("ID " + s.getId() + " has no icon ",
+                    s.hasIconFile() || s.hasIconResource() || s.getIcon() != null);
         }
         return actualShortcuts;
     }
@@ -1959,4 +2053,31 @@
         return ri(PACKAGE_FALLBACK_LAUNCHER, PACKAGE_FALLBACK_LAUNCHER_NAME, true,
                 PACKAGE_FALLBACK_LAUNCHER_PRIORITY);
     }
+
+    protected void makeCallerForeground() {
+        try {
+            mService.mUidObserver.onUidStateChanged(
+                    mInjectedCallingUid, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
+        }
+    }
+
+    protected void makeCallerBackground() {
+        try {
+            mService.mUidObserver.onUidStateChanged(
+                    mInjectedCallingUid, ActivityManager.PROCESS_STATE_TOP_SLEEPING);
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
+        }
+    }
+
+    protected void publishManifestShortcutsAsCaller(int resId) {
+        addManifestShortcutResource(
+                new ComponentName(getCallingPackage(), ShortcutActivity.class.getName()),
+                resId);
+        updatePackageVersion(getCallingPackage(), 1);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageAddIntent(getCallingPackage(), getCallingUserId()));
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java
index ba4dbc1..3684ca0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java
@@ -31,7 +31,8 @@
 import java.util.List;
 
 /**
- * Tests for {@link ShortcutService#hasShortcutHostPermissionInner}.
+ * Tests for {@link ShortcutService#hasShortcutHostPermissionInner}, which includes
+ * {@link ShortcutService#getDefaultLauncher}.
  */
 @SmallTest
 public class ShortcutManagerTest6 extends BaseShortcutManagerTest {
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java
new file mode 100644
index 0000000..fbf0ed2
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java
@@ -0,0 +1,1228 @@
+/*
+ * 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 static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertForLauncherCallbackNoThrow;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.annotation.Nullable;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.content.pm.LauncherApps;
+import android.content.pm.LauncherApps.PinItemRequest;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
+import android.graphics.drawable.Icon;
+import android.os.UserHandle;
+import android.test.MoreAsserts;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Pair;
+
+import com.android.frameworks.servicestests.R;
+
+import org.mockito.ArgumentCaptor;
+
+/**
+ * Tests for {@link ShortcutManager#requestPinShortcut} and relevant APIs.
+ *
+ m FrameworksServicesTests &&
+ adb install \
+ -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
+ adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest8 \
+ -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+
+ * TODO for CTS
+ * - Foreground check.
+ * - Reading icons from requested shortcuts.
+ * - Invalid pre-approved token.
+ */
+@SmallTest
+public class ShortcutManagerTest8 extends BaseShortcutManagerTest {
+    private ShortcutRequestPinProcessor mProcessor;
+
+    @Override
+    protected void initService() {
+        super.initService();
+        mProcessor = mService.getShortcutRequestPinProcessorForTest();
+    }
+
+    @Override
+    protected void setCaller(String packageName, int userId) {
+        super.setCaller(packageName, userId);
+
+        // Note during this test, assume all callers are in the foreground by default.
+        makeCallerForeground();
+    }
+
+    public void testGetParentOrSelfUserId() {
+        assertEquals(USER_0, mService.getParentOrSelfUserId(USER_0));
+        assertEquals(USER_10, mService.getParentOrSelfUserId(USER_10));
+        assertEquals(USER_11, mService.getParentOrSelfUserId(USER_11));
+        assertEquals(USER_0, mService.getParentOrSelfUserId(USER_P0));
+    }
+
+    public void testIsRequestPinShortcutSupported() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+        setDefaultLauncher(USER_10, mMainActivityFetcher.apply(LAUNCHER_2, USER_10));
+
+        Pair<ComponentName, Integer> actual;
+        // User 0
+        actual = mProcessor.getRequestPinShortcutConfirmationActivity(USER_0);
+
+        assertEquals(LAUNCHER_1, actual.first.getPackageName());
+        assertEquals(PIN_CONFIRM_ACTIVITY_CLASS, actual.first.getClassName());
+        assertEquals(USER_0, (int) actual.second);
+
+        // User 10
+        actual = mProcessor.getRequestPinShortcutConfirmationActivity(USER_10);
+
+        assertEquals(LAUNCHER_2, actual.first.getPackageName());
+        assertEquals(PIN_CONFIRM_ACTIVITY_CLASS, actual.first.getClassName());
+        assertEquals(USER_10, (int) actual.second);
+
+        // User P0 -> managed profile, return user-0's launcher.
+        actual = mProcessor.getRequestPinShortcutConfirmationActivity(USER_P0);
+
+        assertEquals(LAUNCHER_1, actual.first.getPackageName());
+        assertEquals(PIN_CONFIRM_ACTIVITY_CLASS, actual.first.getClassName());
+        assertEquals(USER_0, (int) actual.second);
+
+        // Check from the public API.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.isRequestPinShortcutSupported());
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertTrue(mManager.isRequestPinShortcutSupported());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertTrue(mManager.isRequestPinShortcutSupported());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertTrue(mManager.isRequestPinShortcutSupported());
+        });
+
+        // Now, USER_0's launcher no longer has a confirm activity.
+        mPinConfirmActivityFetcher = (packageName, userId) ->
+                !LAUNCHER_2.equals(packageName)
+                        ? null : new ComponentName(packageName, PIN_CONFIRM_ACTIVITY_CLASS);
+
+        // User 10 -- still has confirm activity.
+        actual = mProcessor.getRequestPinShortcutConfirmationActivity(USER_10);
+
+        assertEquals(LAUNCHER_2, actual.first.getPackageName());
+        assertEquals(PIN_CONFIRM_ACTIVITY_CLASS, actual.first.getClassName());
+        assertEquals(USER_10, (int) actual.second);
+
+        // But user-0 and user p0 no longer has a confirmation activity.
+        assertNull(mProcessor.getRequestPinShortcutConfirmationActivity(USER_0));
+        assertNull(mProcessor.getRequestPinShortcutConfirmationActivity(USER_P0));
+
+        // Check from the public API.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertFalse(mManager.isRequestPinShortcutSupported());
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertFalse(mManager.isRequestPinShortcutSupported());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertTrue(mManager.isRequestPinShortcutSupported());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertFalse(mManager.isRequestPinShortcutSupported());
+        });
+    }
+
+    public void testRequestPinShortcut_notSupported() {
+        // User-0's launcher has no confirmation activity.
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        mPinConfirmActivityFetcher = (packageName, userId) ->
+                !LAUNCHER_2.equals(packageName)
+                        ? null : new ComponentName(packageName, PIN_CONFIRM_ACTIVITY_CLASS);
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            ShortcutInfo s1 = makeShortcut("s1");
+
+            assertFalse(mManager.requestPinShortcut(s1,
+                    /*PendingIntent=*/ null));
+
+            verify(mServiceContext, times(0))
+                    .startActivityAsUser(any(Intent.class), any(UserHandle.class));
+            verify(mServiceContext, times(0))
+                    .sendIntentSender(any(IntentSender.class));
+        });
+
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            ShortcutInfo s1 = makeShortcut("s1");
+
+            assertFalse(mManager.requestPinShortcut(s1,
+                    /*PendingIntent=*/ null));
+
+            verify(mServiceContext, times(0))
+                    .startActivityAsUser(any(Intent.class), any(UserHandle.class));
+            verify(mServiceContext, times(0))
+                    .sendIntentSender(any(IntentSender.class));
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            ShortcutInfo s1 = makeShortcut("s1");
+
+            assertFalse(mManager.requestPinShortcut(s1,
+                    /*PendingIntent=*/ null));
+
+            verify(mServiceContext, times(0))
+                    .startActivityAsUser(any(Intent.class), any(UserHandle.class));
+            verify(mServiceContext, times(0))
+                    .sendIntentSender(any(IntentSender.class));
+        });
+    }
+
+    private void assertPinItemRequestIntent(Intent actualIntent, String expectedPackage) {
+        assertEquals(LauncherApps.ACTION_CONFIRM_PIN_ITEM, actualIntent.getAction());
+        assertEquals(expectedPackage, actualIntent.getComponent().getPackageName());
+        assertEquals(PIN_CONFIRM_ACTIVITY_CLASS,
+                actualIntent.getComponent().getClassName());
+        assertEquals(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK,
+                actualIntent.getFlags());
+    }
+
+    public void testNotForeground() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            makeCallerBackground();
+
+            assertExpectException(IllegalStateException.class, "foreground activity", () -> {
+                assertTrue(mManager.requestPinShortcut(makeShortcut("s1"),
+                        /* resultIntent= */ null));
+            });
+
+            verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+            verify(mServiceContext, times(0)).startActivityAsUser(
+                    any(Intent.class), any(UserHandle.class));
+        });
+    }
+
+    private void assertPinItemRequest(PinItemRequest actualRequest) {
+        assertNotNull(actualRequest);
+
+        assertEquals(PinItemRequest.REQUEST_TYPE_SHORTCUT, actualRequest.getRequestType());
+    }
+
+    /**
+     * Basic flow:
+     * - Launcher supports the feature.
+     * - Shortcut doesn't pre-exist.
+     */
+    private void checkRequestPinShortcut(@Nullable PendingIntent resultIntent) {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+        setDefaultLauncher(USER_10, mMainActivityFetcher.apply(LAUNCHER_2, USER_10));
+
+        final Icon res32x32 = Icon.createWithResource(getTestContext(), R.drawable.black_32x32);
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            ShortcutInfo s1 = makeShortcutWithIcon("s1", res32x32);
+
+            assertTrue(mManager.requestPinShortcut(s1,
+                    resultIntent == null ? null : resultIntent.getIntentSender()));
+
+            verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+
+            // Shortcut shouldn't be registered yet.
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // Check the intent passed to startActivityAsUser().
+            final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
+
+            verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0));
+
+            assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage);
+
+            // Check the request object.
+            final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue());
+
+            assertPinItemRequest(request);
+
+            assertWith(request.getShortcutInfo())
+                    .haveIds("s1")
+                    .areAllOrphan()
+                    .areAllWithNoIntent();
+
+            assertAllHaveIcon(list(request.getShortcutInfo()));
+
+            // Accept the request.
+            assertForLauncherCallbackNoThrow(mLauncherApps,
+                    () -> assertTrue(request.accept()))
+                    .assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_P0)
+                    .haveIds("s1");
+        });
+
+        // This method is always called, even with PI == null.
+        if (resultIntent == null) {
+            verify(mServiceContext, times(1)).sendIntentSender(eq(null));
+        } else {
+            verify(mServiceContext, times(1)).sendIntentSender(any(IntentSender.class));
+        }
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("s1")
+                    .areAllNotDynamic()
+                    .areAllEnabled()
+                    .areAllPinned()
+                    .areAllWithIntent();
+        });
+    }
+
+    public void testRequestPinShortcut() {
+        checkRequestPinShortcut(/* resultIntent=*/ null);
+    }
+
+    public void testRequestPinShortcut_withCallback() {
+        final PendingIntent resultIntent =
+                PendingIntent.getActivity(getTestContext(), 0, new Intent(), 0);
+
+        checkRequestPinShortcut(resultIntent);
+    }
+
+    public void testRequestPinShortcut_dynamicExists() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        final Icon res32x32 = Icon.createWithResource(getTestContext(), R.drawable.black_32x32);
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            // Create dynamic shortcut
+            ShortcutInfo s1 = makeShortcutWithIcon("s1", res32x32);
+            assertTrue(mManager.setDynamicShortcuts(list(s1)));
+
+            assertTrue(mManager.requestPinShortcut(makeShortcutIdOnly("s1"),
+                    /* resultIntent=*/ null));
+
+            verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+
+            assertWith(getCallerShortcuts())
+                    .haveIds("s1")
+                    .areAllDynamic()
+                    .areAllNotPinned();
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // Check the intent passed to startActivityAsUser().
+            final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
+
+            verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0));
+
+            assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage);
+
+            // Check the request object.
+            final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue());
+
+            assertPinItemRequest(request);
+
+            assertWith(request.getShortcutInfo())
+                    .haveIds("s1")
+                    .areAllDynamic()
+                    .areAllNotPinned()
+                    .areAllWithNoIntent();
+
+            assertAllHaveIcon(list(request.getShortcutInfo()));
+
+            // Accept the request.
+            assertTrue(request.accept());
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("s1")
+                    .areAllDynamic()
+                    .areAllEnabled()
+                    .areAllPinned();
+        });
+    }
+
+    public void testRequestPinShortcut_manifestExists() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            publishManifestShortcutsAsCaller(R.xml.shortcut_1);
+
+            assertTrue(mManager.requestPinShortcut(makeShortcutIdOnly("ms1"),
+                    /* resultIntent=*/ null));
+
+            verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+
+            assertWith(getCallerShortcuts())
+                    .haveIds("ms1")
+                    .areAllManifest()
+                    .areAllNotPinned();
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // Check the intent passed to startActivityAsUser().
+            final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
+
+            verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0));
+
+            assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage);
+
+            // Check the request object.
+            final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue());
+
+            assertPinItemRequest(request);
+
+            assertWith(request.getShortcutInfo())
+                    .haveIds("ms1")
+                    .areAllManifest()
+                    .areAllNotPinned()
+                    .areAllWithNoIntent();
+
+            assertAllHaveIcon(list(request.getShortcutInfo()));
+
+            // Accept the request.
+            assertTrue(request.accept());
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("ms1")
+                    .areAllManifest()
+                    .areAllEnabled()
+                    .areAllPinned();
+        });
+    }
+
+    public void testRequestPinShortcut_dynamicExists_alreadyPinned() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"))));
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_P0);
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("s1")
+                    .areAllDynamic()
+                    .areAllPinned();
+
+            assertTrue(mManager.requestPinShortcut(makeShortcutIdOnly("s1"),
+                    /* resultIntent=*/ null));
+
+            // The intent should be sent right away.
+            verify(mServiceContext, times(1)).sendIntentSender(any(IntentSender.class));
+        });
+    }
+
+    public void testRequestPinShortcut_manifestExists_alreadyPinned() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            publishManifestShortcutsAsCaller(R.xml.shortcut_1);
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms1"), HANDLE_USER_P0);
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("ms1")
+                    .areAllManifest()
+                    .areAllPinned();
+
+            assertTrue(mManager.requestPinShortcut(makeShortcutIdOnly("ms1"),
+                    /* resultIntent=*/ null));
+
+            // The intent should be sent right away.
+            verify(mServiceContext, times(1)).sendIntentSender(any(IntentSender.class));
+        });
+    }
+
+    public void testRequestPinShortcut_wasDynamic_alreadyPinned() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"))));
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_P0);
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            mManager.removeAllDynamicShortcuts();
+            assertWith(getCallerShortcuts())
+                    .haveIds("s1")
+                    .areAllNotDynamic()
+                    .areAllEnabled()
+                    .areAllPinned();
+
+            assertTrue(mManager.requestPinShortcut(makeShortcutIdOnly("s1"),
+                    /* resultIntent=*/ null));
+
+            // The intent should be sent right away.
+            verify(mServiceContext, times(1)).sendIntentSender(any(IntentSender.class));
+        });
+    }
+
+    public void testRequestPinShortcut_wasDynamic_disabled_alreadyPinned() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"))));
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_P0);
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            mManager.disableShortcuts(list("s1"));
+
+            assertWith(getCallerShortcuts())
+                    .haveIds("s1")
+                    .areAllNotDynamic()
+                    .areAllDisabled()
+                    .areAllPinned();
+
+            assertExpectException(IllegalArgumentException.class, "exists but disabled", () -> {
+                mManager.requestPinShortcut(makeShortcutIdOnly("s1"),
+                        /* resultIntent=*/ null);
+            });
+
+            // Shouldn't be called.
+            verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+        });
+    }
+
+    public void testRequestPinShortcut_wasManifest_alreadyPinned() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            publishManifestShortcutsAsCaller(R.xml.shortcut_1);
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms1"), HANDLE_USER_P0);
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            publishManifestShortcutsAsCaller(R.xml.shortcut_0);
+
+            assertWith(getCallerShortcuts())
+                    .haveIds("ms1")
+                    .areAllNotManifest()
+                    .areAllDisabled()
+                    .areAllPinned();
+
+            assertExpectException(IllegalArgumentException.class, "exists but disabled", () -> {
+                mManager.requestPinShortcut(makeShortcutIdOnly("ms1"),
+                        /* resultIntent=*/ null);
+            });
+
+            // Shouldn't be called.
+            verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+        });
+    }
+
+    public void testRequestPinShortcut_dynamicExists_alreadyPinnedByAnother() {
+        // Initially all launchers have the shortcut permission, until we call setDefaultLauncher().
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"))));
+        });
+
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_P0);
+        });
+
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("s1")
+                    .areAllDynamic()
+                    .areAllPinned();
+
+            // The shortcut is already pinned, but not by the current launcher, so it'll still
+            // invoke the whole flow.
+            assertTrue(mManager.requestPinShortcut(makeShortcutIdOnly("s1"),
+                    /* resultIntent=*/ null));
+
+            verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // Check the intent passed to startActivityAsUser().
+            final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
+
+            verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0));
+
+            assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage);
+
+            // Check the request object.
+            final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue());
+
+            assertPinItemRequest(request);
+
+            assertWith(request.getShortcutInfo())
+                    .haveIds("s1")
+                    .areAllDynamic()
+                    .areAllNotPinned() // Note it's not pinned by this launcher.
+                    .areAllWithNoIntent();
+
+            // Accept the request.
+            assertTrue(request.accept());
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("s1")
+                    .areAllDynamic()
+                    .areAllEnabled()
+                    .areAllPinned();
+        });
+    }
+
+    public void testRequestPinShortcut_manifestExists_alreadyPinnedByAnother() {
+        // Initially all launchers have the shortcut permission, until we call setDefaultLauncher().
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            publishManifestShortcutsAsCaller(R.xml.shortcut_1);
+        });
+
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms1"), HANDLE_USER_P0);
+        });
+
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("ms1")
+                    .areAllManifest()
+                    .areAllPinned();
+
+            // The shortcut is already pinned, but not by the current launcher, so it'll still
+            // invoke the whole flow.
+            assertTrue(mManager.requestPinShortcut(makeShortcutIdOnly("ms1"),
+                    /* resultIntent=*/ null));
+
+            verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // Check the intent passed to startActivityAsUser().
+            final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
+
+            verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0));
+
+            assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage);
+
+            // Check the request object.
+            final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue());
+
+            assertPinItemRequest(request);
+
+            assertWith(request.getShortcutInfo())
+                    .haveIds("ms1")
+                    .areAllManifest()
+                    .areAllNotPinned() // Note it's not pinned by this launcher.
+                    .areAllWithNoIntent();
+
+            // Accept the request.
+            assertTrue(request.accept());
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("ms1")
+                    .areAllManifest()
+                    .areAllEnabled()
+                    .areAllPinned();
+        });
+    }
+
+    /**
+     * The launcher already has a pinned shortuct.  The new one should be added, not replace
+     * the existing one.
+     */
+    public void testRequestPinShortcut_launcherAlreadyHasPinned() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"), makeShortcut("s2"))));
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_P0);
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertTrue(mManager.requestPinShortcut(makeShortcutIdOnly("s1"),
+                    /* resultIntent=*/ null));
+
+            verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // Check the intent passed to startActivityAsUser().
+            final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
+
+            verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0));
+
+            assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage);
+
+            // Check the request object.
+            final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue());
+
+            assertPinItemRequest(request);
+
+            assertWith(request.getShortcutInfo())
+                    .haveIds("s1")
+                    .areAllDynamic()
+                    .areAllNotPinned()
+                    .areAllWithNoIntent();
+
+            // Accept the request.
+            assertTrue(request.accept());
+
+            assertWith(getShortcutAsLauncher(USER_P0))
+                    .haveIds("s1", "s2")
+                    .areAllDynamic()
+                    .areAllEnabled()
+                    .areAllPinned();
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("s1", "s2")
+                    .areAllDynamic()
+                    .areAllEnabled()
+                    .areAllPinned();
+        });
+    }
+
+    /**
+     * When trying to pin an existing shortcut, the new fields shouldn't override existing fields.
+     */
+    public void testRequestPinShortcut_dynamicExists_titleWontChange() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        final Icon res32x32 = Icon.createWithResource(getTestContext(), R.drawable.black_32x32);
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            // Create dynamic shortcut
+            ShortcutInfo s1 = makeShortcutWithIcon("s1", res32x32);
+            assertTrue(mManager.setDynamicShortcuts(list(s1)));
+
+            assertTrue(mManager.requestPinShortcut(makeShortcutWithShortLabel("s1", "xxx"),
+                    /* resultIntent=*/ null));
+
+            verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+
+            assertWith(getCallerShortcuts())
+                    .haveIds("s1")
+                    .areAllDynamic()
+                    .areAllNotPinned();
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // Check the intent passed to startActivityAsUser().
+            final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
+
+            verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0));
+
+            assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage);
+
+            // Check the request object.
+            final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue());
+
+            assertPinItemRequest(request);
+
+            assertWith(request.getShortcutInfo())
+                    .haveIds("s1")
+                    .areAllDynamic()
+                    .areAllNotPinned()
+                    .areAllWithNoIntent();
+
+            assertAllHaveIcon(list(request.getShortcutInfo()));
+
+            // Accept the request.
+            assertTrue(request.accept());
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("s1")
+                    .areAllDynamic()
+                    .areAllEnabled()
+                    .areAllPinned()
+                    .forShortcutWithId("s1", (si) -> {
+                        // Still the original title.
+                        assertEquals("Title-s1", si.getShortLabel());
+                    });
+        });
+    }
+
+    /**
+     * When trying to pin an existing shortcut, the new fields shouldn't override existing fields.
+     */
+    public void testRequestPinShortcut_manifestExists_titleWontChange() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            publishManifestShortcutsAsCaller(R.xml.shortcut_1);
+
+            assertTrue(mManager.requestPinShortcut(makeShortcutWithShortLabel("ms1", "xxx"),
+                    /* resultIntent=*/ null));
+
+            verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+
+            assertWith(getCallerShortcuts())
+                    .haveIds("ms1")
+                    .areAllManifest()
+                    .areAllNotPinned();
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // Check the intent passed to startActivityAsUser().
+            final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
+
+            verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0));
+
+            assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage);
+
+            // Check the request object.
+            final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue());
+
+            assertPinItemRequest(request);
+
+            assertWith(request.getShortcutInfo())
+                    .haveIds("ms1")
+                    .areAllManifest()
+                    .areAllNotPinned()
+                    .areAllWithNoIntent();
+
+            assertAllHaveIcon(list(request.getShortcutInfo()));
+
+            // Accept the request.
+            assertTrue(request.accept());
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("ms1")
+                    .areAllManifest()
+                    .areAllEnabled()
+                    .areAllPinned()
+                    .forShortcutWithId("ms1", (si) -> {
+                        // Still the original title.
+                        // Title should be something like:
+                        // "string-com.android.test.1-user:20-res:2131034112/en"
+                        MoreAsserts.assertContainsRegex("^string-", si.getShortLabel().toString());
+                    });
+        });
+    }
+
+    /**
+     * The dynamic shortcut existed, but before accepting(), it's removed.  Because the request
+     * has a partial shortcut, accept() should fail.
+     */
+    public void testRequestPinShortcut_dynamicExists_thenRemoved_error() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            // Create dynamic shortcut
+            ShortcutInfo s1 = makeShortcut("s1");
+            assertTrue(mManager.setDynamicShortcuts(list(s1)));
+
+            assertTrue(mManager.requestPinShortcut(makeShortcutIdOnly("s1"),
+                    /* resultIntent=*/ null));
+
+            verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+
+            mManager.removeAllDynamicShortcuts();
+
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // Check the intent passed to startActivityAsUser().
+            final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
+
+            verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0));
+
+            assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage);
+
+            // Check the request object.
+            final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue());
+
+            assertPinItemRequest(request);
+
+            assertWith(request.getShortcutInfo())
+                    .haveIds("s1")
+                    .areAllDynamic()
+                    .areAllNotPinned()
+                    .areAllWithNoIntent();
+
+            // Accept the request -> should fail.
+            assertForLauncherCallbackNoThrow(mLauncherApps,
+                    () -> assertFalse(request.accept()))
+                    .assertNoCallbackCalled();
+        });
+
+        // Intent shouldn't be sent.
+        verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+    }
+
+    /**
+     * The dynamic shortcut existed, but before accepting(), it's removed.  Because the request
+     * has all the mandatory fields, we can go ahead and still publish it.
+     */
+    public void testRequestPinShortcut_dynamicExists_thenRemoved_okay() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            // Create dynamic shortcut
+            ShortcutInfo s1 = makeShortcut("s1");
+            assertTrue(mManager.setDynamicShortcuts(list(s1)));
+
+            assertTrue(mManager.requestPinShortcut(makeShortcutWithShortLabel("s1", "new"),
+                    /* resultIntent=*/ null));
+
+            verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+
+            mManager.removeAllDynamicShortcuts();
+
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // Check the intent passed to startActivityAsUser().
+            final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
+
+            verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0));
+
+            assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage);
+
+            // Check the request object.
+            final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue());
+
+            assertPinItemRequest(request);
+
+            assertWith(request.getShortcutInfo())
+                    .haveIds("s1")
+                    .areAllDynamic()
+                    .areAllNotPinned()
+                    .areAllWithNoIntent();
+
+            // Accept the request -> should fail.
+            assertTrue(request.accept());
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("s1")
+                    .areAllFloating()
+                    .forShortcutWithId("s1", si -> {
+                        assertEquals("new", si.getShortLabel());
+                    });
+        });
+    }
+
+    /**
+     * The manifest shortcut existed, but before accepting(), it's removed.  Because the request
+     * has a partial shortcut, accept() should fail.
+     */
+    public void testRequestPinShortcut_manifestExists_thenRemoved_error() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            publishManifestShortcutsAsCaller(R.xml.shortcut_1);
+
+            assertTrue(mManager.requestPinShortcut(makeShortcutIdOnly("ms1"),
+                    /* resultIntent=*/ null));
+
+            verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+
+            publishManifestShortcutsAsCaller(R.xml.shortcut_0);
+
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // Check the intent passed to startActivityAsUser().
+            final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
+
+            verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0));
+
+            assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage);
+
+            // Check the request object.
+            final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue());
+
+            assertPinItemRequest(request);
+
+            assertWith(request.getShortcutInfo())
+                    .haveIds("ms1")
+                    .areAllManifest()
+                    .areAllNotPinned()
+                    .areAllWithNoIntent();
+
+            // Accept the request -> should fail.
+            assertForLauncherCallbackNoThrow(mLauncherApps,
+                    () -> assertFalse(request.accept()))
+                    .assertNoCallbackCalled();
+        });
+
+        // Intent shouldn't be sent.
+        verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+    }
+
+    /**
+     * The manifest shortcut existed, but before accepting(), it's removed.  Because the request
+     * has all the mandatory fields, we can go ahead and still publish it.
+     */
+    public void testRequestPinShortcut_manifestExists_thenRemoved_okay() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            publishManifestShortcutsAsCaller(R.xml.shortcut_1);
+
+            assertTrue(mManager.requestPinShortcut(makeShortcutWithShortLabel("ms1", "new"),
+                    /* resultIntent=*/ null));
+
+            verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+
+            publishManifestShortcutsAsCaller(R.xml.shortcut_0);
+
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // Check the intent passed to startActivityAsUser().
+            final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
+
+            verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0));
+
+            assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage);
+
+            // Check the request object.
+            final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue());
+
+            assertPinItemRequest(request);
+
+            assertWith(request.getShortcutInfo())
+                    .haveIds("ms1")
+                    .areAllManifest()
+                    .areAllNotPinned()
+                    .areAllWithNoIntent();
+
+
+            // Accept the request -> should fail.
+            assertTrue(request.accept());
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("ms1")
+                    .areAllMutable() // Note it's no longer immutable.
+                    .areAllFloating()
+                    .forShortcutWithId("ms1", si -> {
+                        assertEquals("new", si.getShortLabel());
+                    });
+        });
+    }
+
+    /**
+     * The dynamic shortcut existed, but before accepting(), it's removed.  Because the request
+     * has a partial shortcut, accept() should fail.
+     */
+    public void testRequestPinShortcut_dynamicExists_thenDisabled_error() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            ShortcutInfo s1 = makeShortcut("s1");
+            assertTrue(mManager.setDynamicShortcuts(list(s1)));
+
+            assertTrue(mManager.requestPinShortcut(makeShortcutIdOnly("s1"),
+                    /* resultIntent=*/ null));
+
+            verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+        });
+
+        // Then, pin by another launcher and disable it.
+        // We have to pin it here so that disable() won't remove it.
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_2, USER_0));
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_P0);
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            mManager.disableShortcuts(list("s1"));
+            assertWith(getCallerShortcuts())
+                    .haveIds("s1")
+                    .areAllDisabled();
+        });
+
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // Check the intent passed to startActivityAsUser().
+            final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
+
+            verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0));
+
+            assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage);
+
+            // Check the request object.
+            final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue());
+
+            assertPinItemRequest(request);
+
+            assertWith(request.getShortcutInfo())
+                    .haveIds("s1")
+                    .areAllDynamic()
+                    .areAllNotPinned()
+                    .areAllWithNoIntent();
+
+            // Accept the request -> should fail.
+            assertForLauncherCallbackNoThrow(mLauncherApps,
+                    () -> assertFalse(request.accept()))
+                    .assertNoCallbackCalled();
+
+            // Note s1 is floating and pinned by another launcher, so it shouldn't be
+            // visible here.
+            assertWith(getShortcutAsLauncher(USER_P0))
+                    .isEmpty();
+        });
+
+        // Intent shouldn't be sent.
+        verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("s1")
+                    .areAllDisabled();
+        });
+    }
+
+    /**
+     * The manifest shortcut existed, but before accepting(), it's removed.  Because the request
+     * has a partial shortcut, accept() should fail.
+     */
+    public void testRequestPinShortcut_manifestExists_thenDisabled_error() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            publishManifestShortcutsAsCaller(R.xml.shortcut_1);
+
+            assertTrue(mManager.requestPinShortcut(makeShortcutIdOnly("ms1"),
+                    /* resultIntent=*/ null));
+
+            verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+        });
+
+        // Then, pin by another launcher and disable it.
+        // We have to pin it here so that disable() won't remove it.
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_2, USER_0));
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms1"), HANDLE_USER_P0);
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            publishManifestShortcutsAsCaller(R.xml.shortcut_0);
+            assertWith(getCallerShortcuts())
+                    .haveIds("ms1")
+                    .areAllDisabled();
+        });
+
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // Check the intent passed to startActivityAsUser().
+            final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
+
+            verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0));
+
+            assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage);
+
+            // Check the request object.
+            final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue());
+
+            assertPinItemRequest(request);
+
+            assertWith(request.getShortcutInfo())
+                    .haveIds("ms1")
+                    .areAllManifest()
+                    .areAllNotPinned()
+                    .areAllWithNoIntent();
+
+            // Accept the request -> should fail.
+            assertForLauncherCallbackNoThrow(mLauncherApps,
+                    () -> assertFalse(request.accept()))
+                    .assertNoCallbackCalled();
+
+            // Note ms1 is floating and pinned by another launcher, so it shouldn't be
+            // visible here.
+            assertWith(getShortcutAsLauncher(USER_P0))
+                    .isEmpty();
+        });
+
+        // Intent shouldn't be sent.
+        verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("ms1")
+                    .areAllDisabled();
+        });
+    }
+
+    // TODO More tests:
+
+    // Cancel previous pending request and release memory?
+
+    // Check the launcher callback too.
+
+    // Missing fields -- pre and post, both.
+}
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 40d8ac0..9b2c94e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -241,15 +241,14 @@
         }
     }
 
-    // Make sure createProfile would fail if we have DISALLOW_ADD_USER.
+    // Make sure createUser would fail if we have DISALLOW_ADD_USER.
     @MediumTest
-    public void testCreateProfileForUser_disallowAddUser() throws Exception {
+    public void testCreateUser_disallowAddUser() throws Exception {
         final int primaryUserId = mUserManager.getPrimaryUser().id;
         final UserHandle primaryUserHandle = new UserHandle(primaryUserId);
         mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, true, primaryUserHandle);
         try {
-            UserInfo userInfo = createProfileForUser("Managed",
-                    UserInfo.FLAG_MANAGED_PROFILE, primaryUserId);
+            UserInfo userInfo = createUser("SecondaryUser", /*flags=*/ 0);
             assertNull(userInfo);
         } finally {
             mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, false,
@@ -257,17 +256,51 @@
         }
     }
 
-    // Make sure createProfileEvenWhenDisallowedForUser bypass DISALLOW_ADD_USER.
+    // Make sure createProfile would fail if we have DISALLOW_ADD_MANAGED_PROFILE.
+    @MediumTest
+    public void testCreateProfileForUser_disallowAddManagedProfile() throws Exception {
+        final int primaryUserId = mUserManager.getPrimaryUser().id;
+        final UserHandle primaryUserHandle = new UserHandle(primaryUserId);
+        mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, true,
+                primaryUserHandle);
+        try {
+            UserInfo userInfo = createProfileForUser("Managed",
+                    UserInfo.FLAG_MANAGED_PROFILE, primaryUserId);
+            assertNull(userInfo);
+        } finally {
+            mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, false,
+                    primaryUserHandle);
+        }
+    }
+
+    // Make sure createProfileEvenWhenDisallowedForUser bypass DISALLOW_ADD_MANAGED_PROFILE.
     @MediumTest
     public void testCreateProfileForUserEvenWhenDisallowed() throws Exception {
         final int primaryUserId = mUserManager.getPrimaryUser().id;
         final UserHandle primaryUserHandle = new UserHandle(primaryUserId);
-        mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, true, primaryUserHandle);
+        mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, true,
+                primaryUserHandle);
         try {
             UserInfo userInfo = createProfileEvenWhenDisallowedForUser("Managed",
                     UserInfo.FLAG_MANAGED_PROFILE, primaryUserId);
             assertNotNull(userInfo);
         } finally {
+            mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, false,
+                    primaryUserHandle);
+        }
+    }
+
+    // createProfile succeeds even if DISALLOW_ADD_USER is set
+    @MediumTest
+    public void testCreateProfileForUser_disallowAddUser() throws Exception {
+        final int primaryUserId = mUserManager.getPrimaryUser().id;
+        final UserHandle primaryUserHandle = new UserHandle(primaryUserId);
+        mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, true, primaryUserHandle);
+        try {
+            UserInfo userInfo = createProfileForUser("Managed",
+                    UserInfo.FLAG_MANAGED_PROFILE, primaryUserId);
+            assertNotNull(userInfo);
+        } finally {
             mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, false,
                     primaryUserHandle);
         }
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index 162a1a9..01808cb 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -26,6 +26,7 @@
 import java.util.ArrayList;
 
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
 import static org.junit.Assert.assertEquals;
 
 /**
@@ -77,10 +78,12 @@
         assertEquals(sNavBarWindow, windows.get(2));
         assertEquals(sImeWindow, windows.get(1));
         assertEquals(sImeDialogWindow, windows.get(0));
+
+        exitingAppWindow.removeImmediately();
     }
 
     @Test
-    public void testForAllWindows_WithImeTarget() throws Exception {
+    public void testForAllWindows_WithAppImeTarget() throws Exception {
         final WindowState imeAppTarget =
                 createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "imeAppTarget");
 
@@ -121,4 +124,83 @@
         sWm.mInputMethodTarget = null;
         imeAppTarget.removeImmediately();
     }
+
+    @Test
+    public void testForAllWindows_WithStatusBarImeTarget() throws Exception {
+
+        sWm.mInputMethodTarget = sStatusBarWindow;
+
+        final ArrayList<WindowState> windows = new ArrayList();
+
+        // Test forward traversal.
+        sDisplayContent.forAllWindows(w -> {windows.add(w);}, false /* traverseTopToBottom */);
+
+        assertEquals(sWallpaperWindow, windows.get(0));
+        assertEquals(sChildAppWindowBelow, windows.get(1));
+        assertEquals(sAppWindow, windows.get(2));
+        assertEquals(sChildAppWindowAbove, windows.get(3));
+        assertEquals(sDockedDividerWindow, windows.get(4));
+        assertEquals(sStatusBarWindow, windows.get(5));
+        assertEquals(sImeWindow, windows.get(6));
+        assertEquals(sImeDialogWindow, windows.get(7));
+        assertEquals(sNavBarWindow, windows.get(8));
+
+        // Test backward traversal.
+        windows.clear();
+        sDisplayContent.forAllWindows(w -> {windows.add(w);}, true /* traverseTopToBottom */);
+
+        assertEquals(sWallpaperWindow, windows.get(8));
+        assertEquals(sChildAppWindowBelow, windows.get(7));
+        assertEquals(sAppWindow, windows.get(6));
+        assertEquals(sChildAppWindowAbove, windows.get(5));
+        assertEquals(sDockedDividerWindow, windows.get(4));
+        assertEquals(sStatusBarWindow, windows.get(3));
+        assertEquals(sImeWindow, windows.get(2));
+        assertEquals(sImeDialogWindow, windows.get(1));
+        assertEquals(sNavBarWindow, windows.get(0));
+
+        // Clean-up
+        sWm.mInputMethodTarget = null;
+    }
+
+    @Test
+    public void testForAllWindows_WithInBetweenWindowToken() throws Exception {
+        // This window is set-up to be z-ordered between some windows that go in the same token like
+        // the nav bar and status bar.
+        final WindowState voiceInteractionWindow = createWindow(null, TYPE_VOICE_INTERACTION,
+                sDisplayContent, "voiceInteractionWindow");
+
+        final ArrayList<WindowState> windows = new ArrayList();
+
+        // Test forward traversal.
+        sDisplayContent.forAllWindows(w -> {windows.add(w);}, false /* traverseTopToBottom */);
+
+        assertEquals(sWallpaperWindow, windows.get(0));
+        assertEquals(sChildAppWindowBelow, windows.get(1));
+        assertEquals(sAppWindow, windows.get(2));
+        assertEquals(sChildAppWindowAbove, windows.get(3));
+        assertEquals(sDockedDividerWindow, windows.get(4));
+        assertEquals(voiceInteractionWindow, windows.get(5));
+        assertEquals(sStatusBarWindow, windows.get(6));
+        assertEquals(sNavBarWindow, windows.get(7));
+        assertEquals(sImeWindow, windows.get(8));
+        assertEquals(sImeDialogWindow, windows.get(9));
+
+        // Test backward traversal.
+        windows.clear();
+        sDisplayContent.forAllWindows(w -> {windows.add(w);}, true /* traverseTopToBottom */);
+
+        assertEquals(sWallpaperWindow, windows.get(9));
+        assertEquals(sChildAppWindowBelow, windows.get(8));
+        assertEquals(sAppWindow, windows.get(7));
+        assertEquals(sChildAppWindowAbove, windows.get(6));
+        assertEquals(sDockedDividerWindow, windows.get(5));
+        assertEquals(voiceInteractionWindow, windows.get(4));
+        assertEquals(sStatusBarWindow, windows.get(3));
+        assertEquals(sNavBarWindow, windows.get(2));
+        assertEquals(sImeWindow, windows.get(1));
+        assertEquals(sImeDialogWindow, windows.get(0));
+
+        voiceInteractionWindow.removeImmediately();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
index b10c273..ef6ee32 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
@@ -76,7 +76,7 @@
         final Rect mInsetBounds = new Rect();
         boolean mFullscreenForTest = true;
         TaskWithBounds(Rect bounds) {
-            super(0, mStubStack, 0, sWm, null, null, false);
+            super(0, mStubStack, 0, sWm, null, null, false, 0, false);
             mBounds = bounds;
         }
         @Override
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index ab6968b..41bf646 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -83,7 +83,7 @@
                 createWindow(null, TYPE_INPUT_METHOD_DIALOG, sDisplayContent, "sImeDialogWindow");
         sStatusBarWindow = createWindow(null, TYPE_STATUS_BAR, sDisplayContent, "sStatusBarWindow");
         sNavBarWindow =
-                createWindow(null, TYPE_NAVIGATION_BAR, sStatusBarWindow.mToken, "sNavBarWindow");
+                createWindow(null, TYPE_NAVIGATION_BAR, sDisplayContent, "sNavBarWindow");
         sDockedDividerWindow =
                 createWindow(null, TYPE_DOCK_DIVIDER, sDisplayContent, "sDockedDividerWindow");
         sAppWindow = createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "sAppWindow");
@@ -106,10 +106,10 @@
         final int stackId = sNextStackId++;
         dc.addStackToDisplay(stackId, true);
         final TaskStack stack = sWm.mStackIdToStack.get(stackId);
-        final Task task = new Task(sNextTaskId++, stack, 0, sWm, null, EMPTY, false);
+        final Task task = new Task(sNextTaskId++, stack, 0, sWm, null, EMPTY, false, 0, false);
         stack.addTask(task, true);
         final TestAppWindowToken token = new TestAppWindowToken(dc);
-        task.addAppToken(0, token, 0, false);
+        task.addChild(token, 0);
         return token;
     }
 
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 6e74deb..a664f21 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
@@ -729,6 +729,10 @@
         return new ShortcutListAsserter(list);
     }
 
+    public static ShortcutListAsserter assertWith(ShortcutInfo... list) {
+        return assertWith(list(list));
+    }
+
     /**
      * New style assertion that allows chained calls.
      */
@@ -886,6 +890,30 @@
             return this;
         }
 
+        public ShortcutListAsserter areAllFloating() {
+            forAllShortcuts(s -> assertTrue("id=" + s.getId(),
+                    s.isPinned() && !s.isDeclaredInManifest() && !s.isDynamic()));
+            return this;
+        }
+
+        public ShortcutListAsserter areAllNotFloating() {
+            forAllShortcuts(s -> assertTrue("id=" + s.getId(),
+                    !(s.isPinned() && !s.isDeclaredInManifest() && !s.isDynamic())));
+            return this;
+        }
+
+        public ShortcutListAsserter areAllOrphan() {
+            forAllShortcuts(s -> assertTrue("id=" + s.getId(),
+                    !s.isPinned() && !s.isDeclaredInManifest() && !s.isDynamic()));
+            return this;
+        }
+
+        public ShortcutListAsserter areAllNotOrphan() {
+            forAllShortcuts(s -> assertTrue("id=" + s.getId(),
+                    s.isPinned() || s.isDeclaredInManifest() || s.isDynamic()));
+            return this;
+        }
+
         public ShortcutListAsserter areAllWithKeyFieldsOnly() {
             forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.hasKeyFieldsOnly()));
             return this;
@@ -906,6 +934,16 @@
             return this;
         }
 
+        public ShortcutListAsserter areAllWithIntent() {
+            forAllShortcuts(s -> assertNotNull("id=" + s.getId(), s.getIntent()));
+            return this;
+        }
+
+        public ShortcutListAsserter areAllWithNoIntent() {
+            forAllShortcuts(s -> assertNull("id=" + s.getId(), s.getIntent()));
+            return this;
+        }
+
         public ShortcutListAsserter forAllShortcuts(Consumer<ShortcutInfo> sa) {
             boolean found = false;
             for (int i = 0; i < mList.size(); i++) {
@@ -1064,6 +1102,16 @@
         return asserter;
     }
 
+    public static LauncherCallbackAsserter assertForLauncherCallbackNoThrow(
+            LauncherApps launcherApps, Runnable body) {
+        try {
+            return assertForLauncherCallback(launcherApps, body);
+        } catch (InterruptedException e) {
+            fail("Caught InterruptedException");
+            return null; // Never happens.
+        }
+    }
+
     public static void retryUntil(BooleanSupplier checker, String message) {
         retryUntil(checker, message, 30);
     }
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index f541f70..cb32d1f 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -121,6 +121,23 @@
         endTime = timeStamp;
     }
 
+    void updateChooserCounts(String packageName, String category, String action) {
+        UsageStats usageStats = getOrCreateUsageStats(packageName);
+        if (usageStats.mChooserCounts == null) {
+            usageStats.mChooserCounts = new ArrayMap<>();
+        }
+        ArrayMap<String, Integer> chooserCounts;
+        final int idx = usageStats.mChooserCounts.indexOfKey(action);
+        if (idx < 0) {
+            chooserCounts = new ArrayMap<>();
+            usageStats.mChooserCounts.put(action, chooserCounts);
+        } else {
+            chooserCounts = usageStats.mChooserCounts.valueAt(idx);
+        }
+        int currentCount = chooserCounts.getOrDefault(category, 0);
+        chooserCounts.put(category, currentCount + 1);
+    }
+
     void updateConfigurationStats(Configuration config, long timeStamp) {
         if (activeConfiguration != null) {
             ConfigurationStats activeStats = configurations.get(activeConfiguration);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index 849262e..1b28db7 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -17,6 +17,7 @@
 package com.android.server.usage;
 
 import android.app.usage.TimeSparseArray;
+import android.app.usage.UsageStats;
 import android.app.usage.UsageStatsManager;
 import android.os.Build;
 import android.util.AtomicFile;
@@ -502,6 +503,12 @@
             pruneFilesOlderThan(mIntervalDirs[UsageStatsManager.INTERVAL_DAILY],
                     mCal.getTimeInMillis());
 
+            mCal.setTimeInMillis(currentTimeMillis);
+            mCal.addDays(-14);
+            for (int i = 0; i < mIntervalDirs.length; ++i) {
+                pruneChooserCountsOlderThan(mIntervalDirs[i], mCal.getTimeInMillis());
+            }
+
             // We must re-index our file list or we will be trying to read
             // deleted files.
             indexFilesLocked();
@@ -531,6 +538,43 @@
         }
     }
 
+    private static void pruneChooserCountsOlderThan(File dir, long expiryTime) {
+        File[] files = dir.listFiles();
+        if (files != null) {
+            for (File f : files) {
+                String path = f.getPath();
+                if (path.endsWith(BAK_SUFFIX)) {
+                    f = new File(path.substring(0, path.length() - BAK_SUFFIX.length()));
+                }
+
+                long beginTime;
+                try {
+                    beginTime = UsageStatsXml.parseBeginTime(f);
+                } catch (IOException e) {
+                    beginTime = 0;
+                }
+
+                if (beginTime < expiryTime) {
+                    try {
+                        final AtomicFile af = new AtomicFile(f);
+                        final IntervalStats stats = new IntervalStats();
+                        UsageStatsXml.read(af, stats);
+                        final int pkgCount = stats.packageStats.size();
+                        for (int i = 0; i < pkgCount; i++) {
+                            UsageStats pkgStats = stats.packageStats.valueAt(i);
+                            if (pkgStats.mChooserCounts != null) {
+                                pkgStats.mChooserCounts.clear();
+                            }
+                        }
+                        UsageStatsXml.write(af, stats);
+                    } catch (IOException e) {
+                        Slog.e(TAG, "Failed to delete chooser counts from usage stats file", e);
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * Update the stats in the database. They may not be written to disk immediately.
      */
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 515370f..4bfc3df 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -1379,6 +1379,31 @@
             }
             UsageStatsService.this.dump(args, pw);
         }
+
+        @Override
+        public void reportChooserSelection(String packageName, int userId, String contentType,
+                                           String[] annotations, String action) {
+            if (packageName == null) {
+                Slog.w(TAG, "Event report user selecting a null package");
+                return;
+            }
+
+            UsageEvents.Event event = new UsageEvents.Event();
+            event.mPackage = packageName;
+
+            // This will later be converted to system time.
+            event.mTimeStamp = SystemClock.elapsedRealtime();
+
+            event.mEventType = Event.CHOOSER_ACTION;
+
+            event.mAction = action;
+
+            event.mContentType = contentType;
+
+            event.mContentAnnotations = annotations;
+
+            mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget();
+        }
     }
 
     /**
diff --git a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
index 03cee9c..96f3305 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
@@ -26,6 +26,7 @@
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageStats;
 import android.content.res.Configuration;
+import android.util.ArrayMap;
 
 import java.io.IOException;
 import java.net.ProtocolException;
@@ -37,6 +38,11 @@
     private static final String PACKAGES_TAG = "packages";
     private static final String PACKAGE_TAG = "package";
 
+    private static final String CHOOSER_COUNT_TAG = "chosen_action";
+    private static final String CATEGORY_TAG = "category";
+    private static final String NAME = "name";
+    private static final String COUNT = "count";
+
     private static final String CONFIGURATIONS_TAG = "configurations";
     private static final String CONFIG_TAG = "config";
 
@@ -59,7 +65,7 @@
     private static final String TIME_ATTR = "time";
 
     private static void loadUsageStats(XmlPullParser parser, IntervalStats statsOut)
-            throws IOException {
+            throws XmlPullParserException, IOException {
         final String pkg = parser.getAttributeValue(null, PACKAGE_ATTR);
         if (pkg == null) {
             throw new ProtocolException("no " + PACKAGE_ATTR + " attribute present");
@@ -72,6 +78,51 @@
                 parser, LAST_TIME_ACTIVE_ATTR);
         stats.mTotalTimeInForeground = XmlUtils.readLongAttribute(parser, TOTAL_TIME_ACTIVE_ATTR);
         stats.mLastEvent = XmlUtils.readIntAttribute(parser, LAST_EVENT_ATTR);
+        int eventCode;
+        while ((eventCode = parser.next()) != XmlPullParser.END_DOCUMENT) {
+            final String tag = parser.getName();
+            if (eventCode == XmlPullParser.END_TAG && tag.equals(PACKAGE_TAG)) {
+                break;
+            }
+            if (eventCode != XmlPullParser.START_TAG) {
+                continue;
+            }
+            if (tag.equals(CHOOSER_COUNT_TAG)) {
+                String action = XmlUtils.readStringAttribute(parser, NAME);
+                loadChooserCounts(parser, stats, action);
+            }
+        }
+    }
+
+    private static void loadChooserCounts(
+            XmlPullParser parser, UsageStats usageStats, String action)
+            throws XmlPullParserException, IOException {
+        if (action == null) {
+            return;
+        }
+        if (usageStats.mChooserCounts == null) {
+            usageStats.mChooserCounts = new ArrayMap<>();
+        }
+        if (!usageStats.mChooserCounts.containsKey(action)) {
+            ArrayMap<String, Integer> counts = new ArrayMap<>();
+            usageStats.mChooserCounts.put(action, counts);
+        }
+
+        int eventCode;
+        while ((eventCode = parser.next()) != XmlPullParser.END_DOCUMENT) {
+            final String tag = parser.getName();
+            if (eventCode == XmlPullParser.END_TAG && tag.equals(CHOOSER_COUNT_TAG)) {
+                break;
+            }
+            if (eventCode != XmlPullParser.START_TAG) {
+                continue;
+            }
+            if (tag.equals(CATEGORY_TAG)) {
+                String category = XmlUtils.readStringAttribute(parser, NAME);
+                int count = XmlUtils.readIntAttribute(parser, COUNT);
+                usageStats.mChooserCounts.get(action).put(category, count);
+            }
+        }
     }
 
     private static void loadConfigStats(XmlPullParser parser, IntervalStats statsOut)
@@ -135,10 +186,45 @@
         XmlUtils.writeStringAttribute(xml, PACKAGE_ATTR, usageStats.mPackageName);
         XmlUtils.writeLongAttribute(xml, TOTAL_TIME_ACTIVE_ATTR, usageStats.mTotalTimeInForeground);
         XmlUtils.writeIntAttribute(xml, LAST_EVENT_ATTR, usageStats.mLastEvent);
-
+        writeChooserCounts(xml, usageStats);
         xml.endTag(null, PACKAGE_TAG);
     }
 
+    private static void writeChooserCounts(XmlSerializer xml, final UsageStats usageStats)
+            throws IOException {
+        if (usageStats == null || usageStats.mChooserCounts == null ||
+                usageStats.mChooserCounts.keySet().isEmpty()) {
+            return;
+        }
+        final int chooserCountSize = usageStats.mChooserCounts.size();
+        for (int i = 0; i < chooserCountSize; i++) {
+            final String action = usageStats.mChooserCounts.keyAt(i);
+            final ArrayMap<String, Integer> counts = usageStats.mChooserCounts.valueAt(i);
+            if (action == null || counts == null || counts.isEmpty()) {
+                continue;
+            }
+            xml.startTag(null, CHOOSER_COUNT_TAG);
+            XmlUtils.writeStringAttribute(xml, NAME, action);
+            writeCountsForAction(xml, counts);
+            xml.endTag(null, CHOOSER_COUNT_TAG);
+        }
+    }
+
+    private static void writeCountsForAction(XmlSerializer xml, ArrayMap<String, Integer> counts)
+            throws IOException {
+        final int countsSize = counts.size();
+        for (int i = 0; i < countsSize; i++) {
+            String key = counts.keyAt(i);
+            int count = counts.valueAt(i);
+            if (count > 0) {
+                xml.startTag(null, CATEGORY_TAG);
+                XmlUtils.writeStringAttribute(xml, NAME, key);
+                XmlUtils.writeIntAttribute(xml, COUNT, count);
+                xml.endTag(null, CATEGORY_TAG);
+            }
+        }
+    }
+
     private static void writeConfigStats(XmlSerializer xml, final IntervalStats stats,
             final ConfigurationStats configStats, boolean isActive) throws IOException {
         xml.startTag(null, CONFIG_TAG);
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 59e4c80..ba770ef 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -183,6 +183,15 @@
         for (IntervalStats stats : mCurrentStats) {
             if (event.mEventType == UsageEvents.Event.CONFIGURATION_CHANGE) {
                 stats.updateConfigurationStats(newFullConfig, event.mTimeStamp);
+            } else if (event.mEventType == UsageEvents.Event.CHOOSER_ACTION) {
+                stats.updateChooserCounts(event.mPackage, event.mContentType, event.mAction);
+                String[] annotations = event.mContentAnnotations;
+                if (annotations != null) {
+                    for (String annotation : annotations) {
+                        // TODO(kanlig): update with confidences of annotations.
+                        stats.updateChooserCounts(event.mPackage, annotation, event.mAction);
+                    }
+                }
             } else {
                 stats.update(event.mPackage, event.mTimeStamp, event.mEventType);
             }
@@ -520,6 +529,32 @@
         }
         pw.decreaseIndent();
 
+        pw.println();
+        pw.increaseIndent();
+        pw.println("ChooserCounts");
+        pw.increaseIndent();
+        for (UsageStats usageStats : pkgStats.values()) {
+            pw.printPair("package", usageStats.mPackageName);
+            if (usageStats.mChooserCounts != null) {
+                final int chooserCountSize = usageStats.mChooserCounts.size();
+                for (int i = 0; i < chooserCountSize; i++) {
+                    final String action = usageStats.mChooserCounts.keyAt(i);
+                    final ArrayMap<String, Integer> counts = usageStats.mChooserCounts.valueAt(i);
+                    final int annotationSize = counts.size();
+                    for (int j = 0; j < annotationSize; j++) {
+                        final String key = counts.keyAt(j);
+                        final int count = counts.valueAt(j);
+                        if (count != 0) {
+                            pw.printPair("ChooserCounts", action + ":" + key + " is " +
+                                    Integer.toString(count));
+                            pw.println();
+                        }
+                    }
+                }
+            }
+            pw.println();
+        }
+
         pw.println("configurations");
         pw.increaseIndent();
         final ArrayMap<Configuration, ConfigurationStats> configStats = stats.configurations;
@@ -593,6 +628,8 @@
                 return "USER_INTERACTION";
             case UsageEvents.Event.SHORTCUT_INVOCATION:
                 return "SHORTCUT_INVOCATION";
+            case UsageEvents.Event.CHOOSER_ACTION:
+                return "CHOOSER_ACTION";
             default:
                 return "UNKNOWN";
         }
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index b86a85b..db7a31a 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -361,8 +361,6 @@
                             UsbManager.removeFunction(persisted, UsbManager.USB_FUNCTION_MTP));
                 }
 
-                setEnabledFunctions(null, false, false);
-
                 String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
                 updateState(state);
 
@@ -456,13 +454,12 @@
             return false;
         }
 
-        private boolean setUsbConfig(String config) {
+        private void setUsbConfig(String config) {
             if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
             // set the new configuration
             // we always set it due to b/23631400, where adbd was getting killed
             // and not restarted due to property timeouts on some devices
             SystemProperties.set(USB_CONFIG_PROPERTY, config);
-            return waitForState(config);
         }
 
         private void setAdbEnabled(boolean enable) {
@@ -557,8 +554,18 @@
                 // Kick the USB stack to close existing connections.
                 setUsbConfig(UsbManager.USB_FUNCTION_NONE);
 
+                if (!waitForState(UsbManager.USB_FUNCTION_NONE)) {
+                    Slog.e(TAG, "Failed to kick USB config");
+                    return false;
+                }
+
                 // Set the new USB configuration.
-                if (!setUsbConfig(functions)) {
+                setUsbConfig(functions);
+
+                // Start up dependent services.
+                updateUsbStateBroadcastIfNeeded(true);
+
+                if (!waitForState(functions)) {
                     Slog.e(TAG, "Failed to switch USB config to " + functions);
                     return false;
                 }
@@ -599,8 +606,12 @@
                 } else {
                     Slog.e(TAG, "nativeGetAccessoryStrings failed");
                 }
-            } else if (!mConnected && !enteringAccessoryMode) {
-                notifyAccessoryModeExit();
+            } else {
+                if (!enteringAccessoryMode) {
+                    notifyAccessoryModeExit();
+                } else if (DEBUG) {
+                    Slog.v(TAG, "Debouncing accessory mode exit");
+                }
             }
         }
 
@@ -641,7 +652,7 @@
             return false;
         }
 
-        private void updateUsbStateBroadcastIfNeeded() {
+        private void updateUsbStateBroadcastIfNeeded(boolean configChanged) {
             // send a sticky broadcast containing current USB state
             Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
@@ -650,6 +661,7 @@
             intent.putExtra(UsbManager.USB_HOST_CONNECTED, mHostConnected);
             intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);
             intent.putExtra(UsbManager.USB_DATA_UNLOCKED, isUsbTransferAllowed() && mUsbDataUnlocked);
+            intent.putExtra(UsbManager.USB_CONFIG_CHANGED, configChanged);
 
             if (mCurrentFunctions != null) {
                 String[] functions = mCurrentFunctions.split(",");
@@ -747,7 +759,7 @@
                         setEnabledFunctions(null, false, false);
                     }
                     if (mBootCompleted) {
-                        updateUsbStateBroadcastIfNeeded();
+                        updateUsbStateBroadcastIfNeeded(false);
                         updateUsbFunctions();
                     }
                     break;
@@ -759,7 +771,7 @@
                     args.recycle();
                     updateUsbNotification();
                     if (mBootCompleted) {
-                        updateUsbStateBroadcastIfNeeded();
+                        updateUsbStateBroadcastIfNeeded(false);
                     }
                     break;
                 case MSG_ENABLE_ADB:
@@ -775,11 +787,11 @@
                 case MSG_SYSTEM_READY:
                     updateUsbNotification();
                     updateAdbNotification();
-                    updateUsbStateBroadcastIfNeeded();
                     updateUsbFunctions();
                     break;
                 case MSG_BOOT_COMPLETED:
                     mBootCompleted = true;
+                    setEnabledFunctions(null, false, false);
                     if (mCurrentAccessory != null) {
                         getCurrentSettings().accessoryAttached(mCurrentAccessory);
                     }
@@ -805,6 +817,9 @@
                     break;
                 }
                 case MSG_ACCESSORY_MODE_ENTER_TIMEOUT: {
+                    if (DEBUG) {
+                        Slog.v(TAG, "Accessory mode enter timeout: " + mConnected);
+                    }
                     if (!mConnected) {
                         notifyAccessoryModeExit();
                     }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index e6354b7..939a3b8 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -165,6 +165,14 @@
     public static final String
             KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool";
 
+    /**
+     * Control whether users receive a simplified network settings UI and improved network
+     * selection.
+     * @hide
+     */
+    public static final String
+            KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool";
+
     /** Control whether users can reach the SIM lock settings. */
     public static final String
             KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool";
@@ -1138,6 +1146,14 @@
     public static final String KEY_PREF_NETWORK_NOTIFICATION_DELAY_INT =
             "network_notification_delay_int";
 
+    /**
+     * Indicates whether the carrier supports 3gpp call forwarding MMI codes while roaming. If
+     * false, the user will be notified that call forwarding is not available when the MMI code
+     * fails.
+     */
+    public static final String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL =
+        "support_3gpp_call_forwarding_while_roaming_bool";
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -1179,6 +1195,7 @@
         sDefaults.putBoolean(KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL, true);
         sDefaults.putBoolean(KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL, false);
         sDefaults.putBoolean(KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, false);
+        sDefaults.putBoolean(KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL, false);
         sDefaults.putBoolean(KEY_HIDE_SIM_LOCK_SETTINGS_BOOL, false);
 
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONED_BOOL, false);
@@ -1340,6 +1357,7 @@
         sDefaults.putBoolean(KEY_PERSIST_LPP_MODE_BOOL, false);
         sDefaults.putStringArray(KEY_CARRIER_WIFI_STRING_ARRAY, null);
         sDefaults.putInt(KEY_PREF_NETWORK_NOTIFICATION_DELAY_INT, -1);
+        sDefaults.putBoolean(KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL, true);
     }
 
     /**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 918ef5e..7797271 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1852,21 +1852,14 @@
     public static final int SIM_STATE_NETWORK_LOCKED = 4;
     /** SIM card state: Ready */
     public static final int SIM_STATE_READY = 5;
-    /** SIM card state: SIM Card is NOT READY
-     *@hide
-     */
+    /** SIM card state: SIM Card is NOT READY */
     public static final int SIM_STATE_NOT_READY = 6;
-    /** SIM card state: SIM Card Error, permanently disabled
-     *@hide
-     */
+    /** SIM card state: SIM Card Error, permanently disabled */
     public static final int SIM_STATE_PERM_DISABLED = 7;
-    /** SIM card state: SIM Card Error, present but faulty
-     *@hide
-     */
+    /** SIM card state: SIM Card Error, present but faulty */
     public static final int SIM_STATE_CARD_IO_ERROR = 8;
     /** SIM card state: SIM Card restricted, present but not usable due to
      * carrier restrictions.
-     *@hide
      */
     public static final int SIM_STATE_CARD_RESTRICTED = 9;
 
@@ -1912,6 +1905,7 @@
      * @see #SIM_STATE_NOT_READY
      * @see #SIM_STATE_PERM_DISABLED
      * @see #SIM_STATE_CARD_IO_ERROR
+     * @see #SIM_STATE_CARD_RESTRICTED
      */
     public int getSimState() {
         int slotIdx = getDefaultSim();
@@ -1949,8 +1943,8 @@
      * @see #SIM_STATE_NOT_READY
      * @see #SIM_STATE_PERM_DISABLED
      * @see #SIM_STATE_CARD_IO_ERROR
+     * @see #SIM_STATE_CARD_RESTRICTED
      */
-    /** {@hide} */
     public int getSimState(int slotIdx) {
         int simState = SubscriptionManager.getSimStateForSlotIdx(slotIdx);
         return simState;
diff --git a/test-runner/Android.mk b/test-runner/Android.mk
index a317994..0e9a485 100644
--- a/test-runner/Android.mk
+++ b/test-runner/Android.mk
@@ -21,7 +21,6 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_JAVA_LIBRARIES := core-oj core-libart junit framework
-LOCAL_STATIC_JAVA_LIBRARIES := junit-runner
 
 LOCAL_MODULE:= android.test.runner
 
diff --git a/test-runner/src/junit/MODULE_LICENSE_CPL b/test-runner/src/junit/MODULE_LICENSE_CPL
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test-runner/src/junit/MODULE_LICENSE_CPL
diff --git a/test-runner/src/junit/README.android b/test-runner/src/junit/README.android
new file mode 100644
index 0000000..1384a1f
--- /dev/null
+++ b/test-runner/src/junit/README.android
@@ -0,0 +1,11 @@
+URL: https://github.com/junit-team/junit4
+License: Common Public License Version 1.0
+License File: cpl-v10.html
+
+This is JUnit 4.10 source that was previously part of the Android Public API.
+Where necessary it has been patched to be compatible (according to Android API
+requirements) with JUnit 3.8.
+
+These are copied here to ensure that the android.test.runner target remains
+compatible with the last version of the Android API (25) that contained these
+classes even when external/junit is upgraded to a later version.
diff --git a/test-runner/src/junit/cpl-v10.html b/test-runner/src/junit/cpl-v10.html
new file mode 100644
index 0000000..36aa208
--- /dev/null
+++ b/test-runner/src/junit/cpl-v10.html
@@ -0,0 +1,125 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
+<HTML>
+<HEAD>
+<TITLE>Common Public License - v 1.0</TITLE>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</HEAD>
+
+<BODY BGCOLOR="#FFFFFF" VLINK="#800000">
+
+
+<P ALIGN="CENTER"><B>Common Public License - v 1.0</B>
+<P><B></B><FONT SIZE="3"></FONT>
+<P><FONT SIZE="3"></FONT><FONT SIZE="2">THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC LICENSE ("AGREEMENT").  ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.</FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"><B>1.  DEFINITIONS</B></FONT>
+<P><FONT SIZE="2">"Contribution" means:</FONT>
+
+<UL><FONT SIZE="2">a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and<BR CLEAR="LEFT">
+b) in the case of each subsequent Contributor:</FONT></UL>
+
+
+<UL><FONT SIZE="2">i)	 	changes to the Program, and</FONT></UL>
+
+
+<UL><FONT SIZE="2">ii)		additions to the Program;</FONT></UL>
+
+
+<UL><FONT SIZE="2">where such changes and/or additions to the Program originate from and are distributed by that particular Contributor.  </FONT><FONT SIZE="2">A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf.  </FONT><FONT SIZE="2">Contributions do not include additions to the Program which:  (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.  </FONT></UL>
+
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">"Contributor" means any person or entity that distributes the Program.</FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">"Licensed Patents " mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.  </FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2">"Program" means the Contributions distributed in accordance with this Agreement.</FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.</FONT>
+<P><FONT SIZE="2"><B></B></FONT>
+<P><FONT SIZE="2"><B>2.  GRANT OF RIGHTS</B></FONT>
+
+<UL><FONT SIZE="2"></FONT><FONT SIZE="2">a)	</FONT><FONT SIZE="2">Subject to the terms of this Agreement, each Contributor hereby grants</FONT><FONT SIZE="2"> Recipient a non-exclusive, worldwide, royalty-free copyright license to</FONT><FONT SIZE="2" COLOR="#FF0000"> </FONT><FONT SIZE="2">reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.</FONT></UL>
+
+
+<UL><FONT SIZE="2"></FONT></UL>
+
+
+<UL><FONT SIZE="2"></FONT><FONT SIZE="2">b) 	Subject to the terms of this Agreement, each Contributor hereby grants </FONT><FONT SIZE="2">Recipient a non-exclusive, worldwide,</FONT><FONT SIZE="2" COLOR="#008000"> </FONT><FONT SIZE="2">royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form.  This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents.  The patent license shall not apply to any other combinations which include the Contribution.  No hardware per se is licensed hereunder.   </FONT></UL>
+
+
+<UL><FONT SIZE="2"></FONT></UL>
+
+
+<UL><FONT SIZE="2">c)	Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity.  Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise.  As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any.  For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.</FONT></UL>
+
+
+<UL><FONT SIZE="2"></FONT></UL>
+
+
+<UL><FONT SIZE="2">d)	Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. </FONT></UL>
+
+
+<UL><FONT SIZE="2"></FONT></UL>
+
+<P><FONT SIZE="2"><B>3.  REQUIREMENTS</B></FONT>
+<P><FONT SIZE="2"><B></B>A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:</FONT>
+
+<UL><FONT SIZE="2">a)	it complies with the terms and conditions of this Agreement; and</FONT></UL>
+
+
+<UL><FONT SIZE="2">b)	its license agreement:</FONT></UL>
+
+
+<UL><FONT SIZE="2">i)	effectively disclaims</FONT><FONT SIZE="2"> on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; </FONT></UL>
+
+
+<UL><FONT SIZE="2">ii) 	effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; </FONT></UL>
+
+
+<UL><FONT SIZE="2">iii)</FONT><FONT SIZE="2">	states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and</FONT></UL>
+
+
+<UL><FONT SIZE="2">iv)	states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.</FONT><FONT SIZE="2" COLOR="#0000FF"> </FONT><FONT SIZE="2" COLOR="#FF0000"></FONT></UL>
+
+
+<UL><FONT SIZE="2" COLOR="#FF0000"></FONT><FONT SIZE="2"></FONT></UL>
+
+<P><FONT SIZE="2">When the Program is made available in source code form:</FONT>
+
+<UL><FONT SIZE="2">a)	it must be made available under this Agreement; and </FONT></UL>
+
+
+<UL><FONT SIZE="2">b)	a copy of this Agreement must be included with each copy of the Program.  </FONT></UL>
+
+<P><FONT SIZE="2"></FONT><FONT SIZE="2" COLOR="#0000FF"><STRIKE></STRIKE></FONT>
+<P><FONT SIZE="2" COLOR="#0000FF"><STRIKE></STRIKE></FONT><FONT SIZE="2">Contributors may not remove or alter any copyright notices contained within the Program.  </FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.  </FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"><B>4.  COMMERCIAL DISTRIBUTION</B></FONT>
+<P><FONT SIZE="2">Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like.  While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors.   Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering.  The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement.  In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations.  The Indemnified Contributor may participate in any such claim at its own expense.</FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">For example, a Contributor might include the Program in a commercial product offering, Product X.  That Contributor is then a Commercial Contributor.  If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone.  Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.</FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2" COLOR="#0000FF"></FONT>
+<P><FONT SIZE="2" COLOR="#0000FF"></FONT><FONT SIZE="2"><B>5.  NO WARRANTY</B></FONT>
+<P><FONT SIZE="2">EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is</FONT><FONT SIZE="2"> solely responsible for determining the appropriateness of using and distributing </FONT><FONT SIZE="2">the Program</FONT><FONT SIZE="2"> and assumes all risks associated with its exercise of rights under this Agreement</FONT><FONT SIZE="2">, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, </FONT><FONT SIZE="2">programs or equipment, and unavailability or interruption of operations</FONT><FONT SIZE="2">.  </FONT><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2"><B>6.  DISCLAIMER OF LIABILITY</B></FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2">EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES </FONT><FONT SIZE="2">(INCLUDING WITHOUT LIMITATION LOST PROFITS),</FONT><FONT SIZE="2"> HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"><B>7.  GENERAL</B></FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2">If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.</FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">If Recipient institutes patent litigation against a Contributor with respect to a patent applicable to software (including a cross-claim or counterclaim in a lawsuit), then any patent licenses granted by that Contributor to such Recipient under this Agreement shall terminate as of the date such litigation is filed.  In addition, if Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. </FONT><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance.  If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable.  However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.  </FONT><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2">Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted  and may only be modified in the following manner. The Agreement Steward reserves the right to </FONT><FONT SIZE="2">publish new versions (including revisions) of this Agreement from time to </FONT><FONT SIZE="2">time. No one other than the Agreement Steward has the right to modify this Agreement. IBM is the initial Agreement Steward.   IBM may assign the responsibility to serve as the Agreement Steward to a suitable separate entity.  </FONT><FONT SIZE="2">Each new version of the Agreement will be given a distinguishing version number.  The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new </FONT><FONT SIZE="2">version.  </FONT><FONT SIZE="2">Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, </FONT><FONT SIZE="2">by implication, estoppel or otherwise</FONT><FONT SIZE="2">.</FONT><FONT SIZE="2">  All rights in the Program not expressly granted under this Agreement are reserved.</FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose.  Each party waives its rights to a jury trial in any resulting litigation.</FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"></FONT>
+
+</BODY>
+
+</HTML>
\ No newline at end of file
diff --git a/test-runner/src/junit/runner/BaseTestRunner.java b/test-runner/src/junit/runner/BaseTestRunner.java
new file mode 100644
index 0000000..e7e0431
--- /dev/null
+++ b/test-runner/src/junit/runner/BaseTestRunner.java
@@ -0,0 +1,340 @@
+package junit.runner;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.text.NumberFormat;
+import java.util.Properties;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestListener;
+import junit.framework.TestSuite;
+
+/**
+ * Base class for all test runners.
+ * This class was born live on stage in Sardinia during XP2000.
+ */
+public abstract class BaseTestRunner implements TestListener {
+	public static final String SUITE_METHODNAME= "suite";
+
+	private static Properties fPreferences;
+	static int fgMaxMessageLength= 500;
+	static boolean fgFilterStack= true;
+	boolean fLoading= true;
+
+    /*
+    * Implementation of TestListener
+    */
+	public synchronized void startTest(Test test) {
+		testStarted(test.toString());
+	}
+
+	protected static void setPreferences(Properties preferences) {
+		fPreferences= preferences;
+	}
+
+	protected static Properties getPreferences() {
+		if (fPreferences == null) {
+			fPreferences= new Properties();
+	 		fPreferences.put("loading", "true");
+ 			fPreferences.put("filterstack", "true");
+  			readPreferences();
+		}
+		return fPreferences;
+	}
+
+	public static void savePreferences() throws IOException {
+		FileOutputStream fos= new FileOutputStream(getPreferencesFile());
+		try {
+			getPreferences().store(fos, "");
+		} finally {
+			fos.close();
+		}
+	}
+
+	// android-changed remove 'static' qualifier for API compatibility
+	public void setPreference(String key, String value) {
+		getPreferences().put(key, value);
+	}
+
+	public synchronized void endTest(Test test) {
+		testEnded(test.toString());
+	}
+
+	public synchronized void addError(final Test test, final Throwable t) {
+		testFailed(TestRunListener.STATUS_ERROR, test, t);
+	}
+
+	public synchronized void addFailure(final Test test, final AssertionFailedError t) {
+		testFailed(TestRunListener.STATUS_FAILURE, test, t);
+	}
+
+	// TestRunListener implementation
+
+	public abstract void testStarted(String testName);
+
+	public abstract void testEnded(String testName);
+
+	public abstract void testFailed(int status, Test test, Throwable t);
+
+	/**
+	 * Returns the Test corresponding to the given suite. This is
+	 * a template method, subclasses override runFailed(), clearStatus().
+	 */
+	public Test getTest(String suiteClassName) {
+		if (suiteClassName.length() <= 0) {
+			clearStatus();
+			return null;
+		}
+		Class<?> testClass= null;
+		try {
+			testClass= loadSuiteClass(suiteClassName);
+		} catch (ClassNotFoundException e) {
+			String clazz= e.getMessage();
+			if (clazz == null)
+				clazz= suiteClassName;
+			runFailed("Class not found \""+clazz+"\"");
+			return null;
+		} catch(Exception e) {
+			runFailed("Error: "+e.toString());
+			return null;
+		}
+		Method suiteMethod= null;
+		try {
+			suiteMethod= testClass.getMethod(SUITE_METHODNAME, new Class[0]);
+	 	} catch(Exception e) {
+	 		// try to extract a test suite automatically
+			clearStatus();
+			return new TestSuite(testClass);
+		}
+		if (! Modifier.isStatic(suiteMethod.getModifiers())) {
+			runFailed("Suite() method must be static");
+			return null;
+		}
+		Test test= null;
+		try {
+			test= (Test)suiteMethod.invoke(null, (Object[])new Class[0]); // static method
+			if (test == null)
+				return test;
+		}
+		catch (InvocationTargetException e) {
+			runFailed("Failed to invoke suite():" + e.getTargetException().toString());
+			return null;
+		}
+		catch (IllegalAccessException e) {
+			runFailed("Failed to invoke suite():" + e.toString());
+			return null;
+		}
+
+		clearStatus();
+		return test;
+	}
+
+	/**
+	 * Returns the formatted string of the elapsed time.
+	 */
+	public String elapsedTimeAsString(long runTime) {
+		return NumberFormat.getInstance().format((double)runTime/1000);
+	}
+
+	/**
+	 * Processes the command line arguments and
+	 * returns the name of the suite class to run or null
+	 */
+	protected String processArguments(String[] args) {
+		String suiteName= null;
+		for (int i= 0; i < args.length; i++) {
+			if (args[i].equals("-noloading")) {
+				setLoading(false);
+			} else if (args[i].equals("-nofilterstack")) {
+				fgFilterStack= false;
+			} else if (args[i].equals("-c")) {
+				if (args.length > i+1)
+					suiteName= extractClassName(args[i+1]);
+				else
+					System.out.println("Missing Test class name");
+				i++;
+			} else {
+				suiteName= args[i];
+			}
+		}
+		return suiteName;
+	}
+
+	/**
+	 * Sets the loading behaviour of the test runner
+	 */
+	public void setLoading(boolean enable) {
+		fLoading= enable;
+	}
+	/**
+	 * Extract the class name from a String in VA/Java style
+	 */
+	public String extractClassName(String className) {
+		if(className.startsWith("Default package for"))
+			return className.substring(className.lastIndexOf(".")+1);
+		return className;
+	}
+
+	/**
+	 * Truncates a String to the maximum length.
+	 */
+	public static String truncate(String s) {
+		if (fgMaxMessageLength != -1 && s.length() > fgMaxMessageLength)
+			s= s.substring(0, fgMaxMessageLength)+"...";
+		return s;
+	}
+
+	/**
+	 * Override to define how to handle a failed loading of
+	 * a test suite.
+	 */
+	protected abstract void runFailed(String message);
+
+	// BEGIN android-changed - add back getLoader() for API compatibility
+	/**
+	 * Returns the loader to be used.
+	 *
+	 * @deprecated not present in JUnit4.10
+	 */
+	public TestSuiteLoader getLoader() {
+		return new StandardTestSuiteLoader();
+	}
+	// END android-changed
+
+	/**
+	 * Returns the loaded Class for a suite name.
+	 */
+	protected Class<?> loadSuiteClass(String suiteClassName) throws ClassNotFoundException {
+		return Class.forName(suiteClassName);
+	}
+
+	/**
+	 * Clears the status message.
+	 */
+	protected void clearStatus() { // Belongs in the GUI TestRunner class
+	}
+
+	protected boolean useReloadingTestSuiteLoader() {
+		return getPreference("loading").equals("true") && fLoading;
+	}
+
+	private static File getPreferencesFile() {
+	 	String home= System.getProperty("user.home");
+ 		return new File(home, "junit.properties");
+ 	}
+
+ 	private static void readPreferences() {
+ 		InputStream is= null;
+ 		try {
+ 			is= new FileInputStream(getPreferencesFile());
+ 			setPreferences(new Properties(getPreferences()));
+			getPreferences().load(is);
+		} catch (IOException e) {
+			try {
+				if (is != null)
+					is.close();
+			} catch (IOException e1) {
+			}
+		}
+ 	}
+
+ 	public static String getPreference(String key) {
+ 		return getPreferences().getProperty(key);
+ 	}
+
+ 	public static int getPreference(String key, int dflt) {
+ 		String value= getPreference(key);
+ 		int intValue= dflt;
+ 		if (value == null)
+ 			return intValue;
+ 		try {
+ 			intValue= Integer.parseInt(value);
+ 	 	} catch (NumberFormatException ne) {
+ 		}
+ 		return intValue;
+ 	}
+
+	/**
+	 * Returns a filtered stack trace
+	 */
+	public static String getFilteredTrace(Throwable t) {
+		StringWriter stringWriter= new StringWriter();
+		PrintWriter writer= new PrintWriter(stringWriter);
+		t.printStackTrace(writer);
+		StringBuffer buffer= stringWriter.getBuffer();
+		String trace= buffer.toString();
+		return BaseTestRunner.getFilteredTrace(trace);
+	}
+
+	// BEGIN android-changed - add back this method for API compatibility
+	/** @deprecated not present in JUnit4.10 */
+	public static boolean inVAJava() {
+		return false;
+	}
+	// END android-changed
+
+	/**
+	 * Filters stack frames from internal JUnit classes
+	 */
+	public static String getFilteredTrace(String stack) {
+		if (showStackRaw())
+			return stack;
+
+		StringWriter sw= new StringWriter();
+		PrintWriter pw= new PrintWriter(sw);
+		StringReader sr= new StringReader(stack);
+		// BEGIN android-changed
+		// Use a sensible default buffer size
+		BufferedReader br= new BufferedReader(sr, 1000);
+		// END android-changed
+
+		String line;
+		try {
+			while ((line= br.readLine()) != null) {
+				if (!filterLine(line))
+					pw.println(line);
+			}
+		} catch (Exception IOException) {
+			return stack; // return the stack unfiltered
+		}
+		return sw.toString();
+	}
+
+	protected static boolean showStackRaw() {
+		return !getPreference("filterstack").equals("true") || fgFilterStack == false;
+	}
+
+	static boolean filterLine(String line) {
+		String[] patterns= new String[] {
+			"junit.framework.TestCase",
+			"junit.framework.TestResult",
+			"junit.framework.TestSuite",
+			"junit.framework.Assert.", // don't filter AssertionFailure
+			"junit.swingui.TestRunner",
+			"junit.awtui.TestRunner",
+			"junit.textui.TestRunner",
+			"java.lang.reflect.Method.invoke("
+		};
+		for (int i= 0; i < patterns.length; i++) {
+			if (line.indexOf(patterns[i]) > 0)
+				return true;
+		}
+		return false;
+	}
+
+ 	static {
+ 		fgMaxMessageLength= getPreference("maxmessage", fgMaxMessageLength);
+ 	}
+
+}
diff --git a/test-runner/src/junit/runner/StandardTestSuiteLoader.java b/test-runner/src/junit/runner/StandardTestSuiteLoader.java
new file mode 100644
index 0000000..808963a
--- /dev/null
+++ b/test-runner/src/junit/runner/StandardTestSuiteLoader.java
@@ -0,0 +1,23 @@
+package junit.runner;
+
+// android-changed - class not present in upstream JUnit 4.10
+// added here to retain BaseTestRunner.getLoader API
+
+/**
+ * The standard test suite loader. It can only load the same class once.
+ * {@hide}
+ */
+public class StandardTestSuiteLoader implements TestSuiteLoader {
+    /**
+     * Uses the system class loader to load the test class
+     */
+    public Class load(String suiteClassName) throws ClassNotFoundException {
+        return Class.forName(suiteClassName);
+    }
+    /**
+     * Uses the system class loader to load the test class
+     */
+    public Class reload(Class aClass) throws ClassNotFoundException {
+        return aClass;
+    }
+}
diff --git a/test-runner/src/junit/runner/TestRunListener.java b/test-runner/src/junit/runner/TestRunListener.java
new file mode 100644
index 0000000..0e95819
--- /dev/null
+++ b/test-runner/src/junit/runner/TestRunListener.java
@@ -0,0 +1,20 @@
+package junit.runner;
+/**
+ * A listener interface for observing the
+ * execution of a test run. Unlike TestListener,
+ * this interface using only primitive objects,
+ * making it suitable for remote test execution.
+ * {@hide} - Not needed for 1.0 SDK
+ */
+ public interface TestRunListener {
+     /* test status constants*/
+     public static final int STATUS_ERROR= 1;
+     public static final int STATUS_FAILURE= 2;
+
+     public void testRunStarted(String testSuiteName, int testCount);
+     public void testRunEnded(long elapsedTime);
+     public void testRunStopped(long elapsedTime);
+     public void testStarted(String testName);
+     public void testEnded(String testName);
+     public void testFailed(int status, String testName, String trace);
+}
diff --git a/test-runner/src/junit/runner/TestSuiteLoader.java b/test-runner/src/junit/runner/TestSuiteLoader.java
new file mode 100644
index 0000000..9cc6d81
--- /dev/null
+++ b/test-runner/src/junit/runner/TestSuiteLoader.java
@@ -0,0 +1,11 @@
+package junit.runner;
+
+/**
+ * An interface to define how a test suite should be loaded.
+ *
+ */
+//  TODO: deprecate
+public interface TestSuiteLoader {
+    abstract public Class load(String suiteClassName) throws ClassNotFoundException;
+    abstract public Class reload(Class aClass) throws ClassNotFoundException;
+}
diff --git a/test-runner/src/junit/runner/Version.java b/test-runner/src/junit/runner/Version.java
new file mode 100644
index 0000000..dd88c03
--- /dev/null
+++ b/test-runner/src/junit/runner/Version.java
@@ -0,0 +1,20 @@
+package junit.runner;
+
+/**
+ * This class defines the current version of JUnit
+ */
+public class Version {
+	private Version() {
+		// don't instantiate
+	}
+
+	public static String id() {
+		return "4.10";
+	}
+
+	// android-changed
+	/** @hide - not needed for public API */
+	public static void main(String[] args) {
+		System.out.println(id());
+	}
+}
diff --git a/test-runner/src/junit/runner/package-info.java b/test-runner/src/junit/runner/package-info.java
new file mode 100644
index 0000000..b746185
--- /dev/null
+++ b/test-runner/src/junit/runner/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Provides JUnit v3.x test runners.
+ */
+package junit.runner;
\ No newline at end of file
diff --git a/test-runner/src/junit/runner/package.html b/test-runner/src/junit/runner/package.html
new file mode 100644
index 0000000..f08fa70
--- /dev/null
+++ b/test-runner/src/junit/runner/package.html
@@ -0,0 +1,5 @@
+<HTML>
+<BODY>
+Utility classes supporting the junit test framework.
+</BODY>
+</HTML>
diff --git a/test-runner/src/junit/textui/ResultPrinter.java b/test-runner/src/junit/textui/ResultPrinter.java
new file mode 100644
index 0000000..b491452
--- /dev/null
+++ b/test-runner/src/junit/textui/ResultPrinter.java
@@ -0,0 +1,144 @@
+
+package junit.textui;
+
+import java.io.PrintStream;
+// android-changed
+// The following line was removed for compatibility with Android libraries.
+// import java.text.NumberFormat;
+import java.util.Enumeration;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestFailure;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+import junit.runner.BaseTestRunner;
+
+public class ResultPrinter implements TestListener {
+	PrintStream fWriter;
+	int fColumn= 0;
+	
+	public ResultPrinter(PrintStream writer) {
+		fWriter= writer;
+	}
+	
+	/* API for use by textui.TestRunner
+	 */
+
+	synchronized void print(TestResult result, long runTime) {
+		printHeader(runTime);
+	    printErrors(result);
+	    printFailures(result);
+	    printFooter(result);
+	}
+
+	void printWaitPrompt() {
+		getWriter().println();
+		getWriter().println("<RETURN> to continue");
+	}
+	
+	/* Internal methods 
+	 */
+
+	protected void printHeader(long runTime) {
+		getWriter().println();
+		getWriter().println("Time: "+elapsedTimeAsString(runTime));
+	}
+	
+	protected void printErrors(TestResult result) {
+		printDefects(result.errors(), result.errorCount(), "error");
+	}
+	
+	protected void printFailures(TestResult result) {
+		printDefects(result.failures(), result.failureCount(), "failure");
+	}
+	
+	protected void printDefects(Enumeration<TestFailure> booBoos, int count, String type) {
+		if (count == 0) return;
+		if (count == 1)
+			getWriter().println("There was " + count + " " + type + ":");
+		else
+			getWriter().println("There were " + count + " " + type + "s:");
+		for (int i= 1; booBoos.hasMoreElements(); i++) {
+			printDefect(booBoos.nextElement(), i);
+		}
+	}
+	
+	public void printDefect(TestFailure booBoo, int count) { // only public for testing purposes
+		printDefectHeader(booBoo, count);
+		printDefectTrace(booBoo);
+	}
+
+	protected void printDefectHeader(TestFailure booBoo, int count) {
+		// I feel like making this a println, then adding a line giving the throwable a chance to print something
+		// before we get to the stack trace.
+		getWriter().print(count + ") " + booBoo.failedTest());
+	}
+
+	protected void printDefectTrace(TestFailure booBoo) {
+		getWriter().print(BaseTestRunner.getFilteredTrace(booBoo.trace()));
+	}
+
+	protected void printFooter(TestResult result) {
+		if (result.wasSuccessful()) {
+			getWriter().println();
+			getWriter().print("OK");
+			getWriter().println (" (" + result.runCount() + " test" + (result.runCount() == 1 ? "": "s") + ")");
+
+		} else {
+			getWriter().println();
+			getWriter().println("FAILURES!!!");
+			getWriter().println("Tests run: "+result.runCount()+ 
+				         ",  Failures: "+result.failureCount()+
+				         ",  Errors: "+result.errorCount());
+		}
+	    getWriter().println();
+	}
+
+
+	/**
+	 * Returns the formatted string of the elapsed time.
+	 * Duplicated from BaseTestRunner. Fix it.
+	 */
+	protected String elapsedTimeAsString(long runTime) {
+		// android-changed
+		// The following line was altered for compatibility with
+		// Android libraries.
+		return Double.toString((double)runTime/1000);
+	}
+
+	public PrintStream getWriter() {
+		return fWriter;
+	}
+	/**
+	 * @see junit.framework.TestListener#addError(Test, Throwable)
+	 */
+	public void addError(Test test, Throwable t) {
+		getWriter().print("E");
+	}
+
+	/**
+	 * @see junit.framework.TestListener#addFailure(Test, AssertionFailedError)
+	 */
+	public void addFailure(Test test, AssertionFailedError t) {
+		getWriter().print("F");
+	}
+
+	/**
+	 * @see junit.framework.TestListener#endTest(Test)
+	 */
+	public void endTest(Test test) {
+	}
+
+	/**
+	 * @see junit.framework.TestListener#startTest(Test)
+	 */
+	public void startTest(Test test) {
+		getWriter().print(".");
+		if (fColumn++ >= 40) {
+			getWriter().println();
+			fColumn= 0;
+		}
+	}
+
+}
diff --git a/test-runner/src/junit/textui/TestRunner.java b/test-runner/src/junit/textui/TestRunner.java
new file mode 100644
index 0000000..046448e
--- /dev/null
+++ b/test-runner/src/junit/textui/TestRunner.java
@@ -0,0 +1,203 @@
+package junit.textui;
+
+
+import java.io.PrintStream;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+import junit.runner.BaseTestRunner;
+import junit.runner.Version;
+
+/**
+ * A command line based tool to run tests.
+ * <pre>
+ * java junit.textui.TestRunner [-wait] TestCaseClass
+ * </pre>
+ * 
+ * <p>TestRunner expects the name of a TestCase class as argument.
+ * If this class defines a static <code>suite</code> method it 
+ * will be invoked and the returned test is run. Otherwise all 
+ * the methods starting with "test" having no arguments are run.</p>
+ * 
+ * <p> When the wait command line argument is given TestRunner
+ * waits until the users types RETURN.</p>
+ * 
+ * <p>TestRunner prints a trace as the tests are executed followed by a
+ * summary at the end.</p>
+ */
+public class TestRunner extends BaseTestRunner {
+	private ResultPrinter fPrinter;
+	
+	public static final int SUCCESS_EXIT= 0;
+	public static final int FAILURE_EXIT= 1;
+	public static final int EXCEPTION_EXIT= 2;
+
+	/**
+	 * Constructs a TestRunner.
+	 */
+	public TestRunner() {
+		this(System.out);
+	}
+
+	/**
+	 * Constructs a TestRunner using the given stream for all the output
+	 */
+	public TestRunner(PrintStream writer) {
+		this(new ResultPrinter(writer));
+	}
+	
+	/**
+	 * Constructs a TestRunner using the given ResultPrinter all the output
+	 */
+	public TestRunner(ResultPrinter printer) {
+		fPrinter= printer;
+	}
+	
+	/**
+	 * Runs a suite extracted from a TestCase subclass.
+	 */
+	static public void run(Class<? extends TestCase> testClass) {
+		run(new TestSuite(testClass));
+	}
+
+	/**
+	 * Runs a single test and collects its results.
+	 * This method can be used to start a test run
+	 * from your program.
+	 * <pre>
+	 * public static void main (String[] args) {
+	 *    test.textui.TestRunner.run(suite());
+	 * }
+	 * </pre>
+	 */
+	static public TestResult run(Test test) {
+		TestRunner runner= new TestRunner();
+		return runner.doRun(test);
+	}
+
+	/**
+	 * Runs a single test and waits until the user
+	 * types RETURN.
+	 */
+	static public void runAndWait(Test suite) {
+		TestRunner aTestRunner= new TestRunner();
+		aTestRunner.doRun(suite, true);
+	}
+
+	@Override
+	public void testFailed(int status, Test test, Throwable t) {
+	}
+	
+	@Override
+	public void testStarted(String testName) {
+	}
+	
+	@Override
+	public void testEnded(String testName) {
+	}
+
+	/**
+	 * Creates the TestResult to be used for the test run.
+	 */
+	protected TestResult createTestResult() {
+		return new TestResult();
+	}
+	
+	public TestResult doRun(Test test) {
+		return doRun(test, false);
+	}
+	
+	public TestResult doRun(Test suite, boolean wait) {
+		TestResult result= createTestResult();
+		result.addListener(fPrinter);
+		long startTime= System.currentTimeMillis();
+		suite.run(result);
+		long endTime= System.currentTimeMillis();
+		long runTime= endTime-startTime;
+		fPrinter.print(result, runTime);
+
+		pause(wait);
+		return result;
+	}
+
+	protected void pause(boolean wait) {
+		if (!wait) return;
+		fPrinter.printWaitPrompt();
+		try {
+			System.in.read();
+		}
+		catch(Exception e) {
+		}
+	}
+	
+	public static void main(String args[]) {
+		TestRunner aTestRunner= new TestRunner();
+		try {
+			TestResult r= aTestRunner.start(args);
+			if (!r.wasSuccessful()) 
+				System.exit(FAILURE_EXIT);
+			System.exit(SUCCESS_EXIT);
+		} catch(Exception e) {
+			System.err.println(e.getMessage());
+			System.exit(EXCEPTION_EXIT);
+		}
+	}
+
+	/**
+	 * Starts a test run. Analyzes the command line arguments and runs the given
+	 * test suite.
+	 */
+	public TestResult start(String args[]) throws Exception {
+		String testCase= "";
+		String method= "";
+		boolean wait= false;
+
+		for (int i= 0; i < args.length; i++) {
+			if (args[i].equals("-wait"))
+				wait= true;
+			else if (args[i].equals("-c"))
+				testCase= extractClassName(args[++i]);
+			else if (args[i].equals("-m")) {
+				String arg= args[++i];
+				int lastIndex= arg.lastIndexOf('.');
+				testCase= arg.substring(0, lastIndex);
+				method= arg.substring(lastIndex + 1);
+			} else if (args[i].equals("-v"))
+				System.err.println("JUnit " + Version.id() + " by Kent Beck and Erich Gamma");
+			else
+				testCase= args[i];
+		}
+
+		if (testCase.equals(""))
+			throw new Exception("Usage: TestRunner [-wait] testCaseName, where name is the name of the TestCase class");
+
+		try {
+			if (!method.equals("")) 
+				return runSingleMethod(testCase, method, wait);
+			Test suite= getTest(testCase);
+			return doRun(suite, wait);
+		} catch (Exception e) {
+			throw new Exception("Could not create and run test suite: " + e);
+		}
+	}
+
+	protected TestResult runSingleMethod(String testCase, String method, boolean wait) throws Exception {
+		Class<? extends TestCase> testClass= loadSuiteClass(testCase).asSubclass(TestCase.class);
+		Test test= TestSuite.createTest(testClass, method);
+		return doRun(test, wait);
+	}
+
+	@Override
+	protected void runFailed(String message) {
+		System.err.println(message);
+		System.exit(FAILURE_EXIT);
+	}
+	
+	public void setPrinter(ResultPrinter printer) {
+		fPrinter= printer;
+	}
+		
+	
+}
\ No newline at end of file
diff --git a/test-runner/src/junit/textui/package-info.java b/test-runner/src/junit/textui/package-info.java
new file mode 100644
index 0000000..2dcc10c
--- /dev/null
+++ b/test-runner/src/junit/textui/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Provides JUnit v3.x command line based tool to run tests.
+ * {@hide}
+ */
+package junit.textui;
\ No newline at end of file
diff --git a/test-runner/src/junit/textui/package.html b/test-runner/src/junit/textui/package.html
new file mode 100644
index 0000000..723f2ae
--- /dev/null
+++ b/test-runner/src/junit/textui/package.html
@@ -0,0 +1,6 @@
+<HTML>
+<BODY>
+Utility classes supporting the junit test framework.
+{@hide} - Not needed for 1.0 SDK
+</BODY>
+</HTML>
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
index 6a064d2..f9cac43 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
@@ -39,13 +39,13 @@
 import android.net.metrics.NetworkEvent;
 import android.net.metrics.RaEvent;
 import android.net.metrics.ValidationProbeEvent;
-
-import junit.framework.TestCase;
-
+import android.test.suitebuilder.annotation.SmallTest;
 import java.util.Arrays;
+import junit.framework.TestCase;
 
 public class IpConnectivityEventBuilderTest extends TestCase {
 
+    @SmallTest
     public void testDefaultNetworkEventSerialization() {
         ConnectivityMetricsEvent ev = describeIpEvent(
                 aType(DefaultNetworkEvent.class),
@@ -58,6 +58,8 @@
         String want = joinLines(
                 "dropped_events: 0",
                 "events <",
+                "  time_ms: 1",
+                "  transport: 0",
                 "  default_network_event <",
                 "    network_id <",
                 "      network_id: 102",
@@ -70,13 +72,13 @@
                 "    transport_types: 2",
                 "    transport_types: 3",
                 "  >",
-                "  time_ms: 1",
                 ">",
                 "version: 2");
 
         verifySerialization(want, ev);
     }
 
+    @SmallTest
     public void testDhcpClientEventSerialization() {
         ConnectivityMetricsEvent ev = describeIpEvent(
                 aType(DhcpClientEvent.class),
@@ -87,19 +89,20 @@
         String want = joinLines(
                 "dropped_events: 0",
                 "events <",
+                "  time_ms: 1",
+                "  transport: 0",
                 "  dhcp_event <",
                 "    duration_ms: 192",
-                "    error_code: 0",
                 "    if_name: \"wlan0\"",
                 "    state_transition: \"SomeState\"",
                 "  >",
-                "  time_ms: 1",
                 ">",
                 "version: 2");
 
         verifySerialization(want, ev);
     }
 
+    @SmallTest
     public void testDhcpErrorEventSerialization() {
         ConnectivityMetricsEvent ev = describeIpEvent(
                 aType(DhcpErrorEvent.class),
@@ -109,19 +112,20 @@
         String want = joinLines(
                 "dropped_events: 0",
                 "events <",
+                "  time_ms: 1",
+                "  transport: 0",
                 "  dhcp_event <",
                 "    duration_ms: 0",
-                "    error_code: 50397184",
                 "    if_name: \"wlan0\"",
-                "    state_transition: \"\"",
+                "    error_code: 50397184",
                 "  >",
-                "  time_ms: 1",
                 ">",
                 "version: 2");
 
         verifySerialization(want, ev);
     }
 
+    @SmallTest
     public void testDnsEventSerialization() {
         ConnectivityMetricsEvent ev = describeIpEvent(
                 aType(DnsEvent.class),
@@ -133,6 +137,8 @@
         String want = joinLines(
                 "dropped_events: 0",
                 "events <",
+                "  time_ms: 1",
+                "  transport: 0",
                 "  dns_lookup_batch <",
                 "    event_types: 1",
                 "    event_types: 1",
@@ -162,13 +168,13 @@
                 "    return_codes: 200",
                 "    return_codes: 178",
                 "  >",
-                "  time_ms: 1",
                 ">",
                 "version: 2");
 
         verifySerialization(want, ev);
     }
 
+    @SmallTest
     public void testIpManagerEventSerialization() {
         ConnectivityMetricsEvent ev = describeIpEvent(
                 aType(IpManagerEvent.class),
@@ -179,18 +185,20 @@
         String want = joinLines(
                 "dropped_events: 0",
                 "events <",
+                "  time_ms: 1",
+                "  transport: 0",
                 "  ip_provisioning_event <",
                 "    event_type: 1",
                 "    if_name: \"wlan0\"",
                 "    latency_ms: 5678",
                 "  >",
-                "  time_ms: 1",
                 ">",
                 "version: 2");
 
         verifySerialization(want, ev);
     }
 
+    @SmallTest
     public void testIpReachabilityEventSerialization() {
         ConnectivityMetricsEvent ev = describeIpEvent(
                 aType(IpReachabilityEvent.class),
@@ -200,17 +208,19 @@
         String want = joinLines(
                 "dropped_events: 0",
                 "events <",
+                "  time_ms: 1",
+                "  transport: 0",
                 "  ip_reachability_event <",
                 "    event_type: 512",
                 "    if_name: \"wlan0\"",
                 "  >",
-                "  time_ms: 1",
                 ">",
                 "version: 2");
 
         verifySerialization(want, ev);
     }
 
+    @SmallTest
     public void testNetworkEventSerialization() {
         ConnectivityMetricsEvent ev = describeIpEvent(
                 aType(NetworkEvent.class),
@@ -221,6 +231,8 @@
         String want = joinLines(
                 "dropped_events: 0",
                 "events <",
+                "  time_ms: 1",
+                "  transport: 0",
                 "  network_event <",
                 "    event_type: 5",
                 "    latency_ms: 20410",
@@ -228,13 +240,13 @@
                 "      network_id: 100",
                 "    >",
                 "  >",
-                "  time_ms: 1",
                 ">",
                 "version: 2");
 
         verifySerialization(want, ev);
     }
 
+    @SmallTest
     public void testValidationProbeEventSerialization() {
         ConnectivityMetricsEvent ev = describeIpEvent(
                 aType(ValidationProbeEvent.class),
@@ -247,6 +259,7 @@
                 "dropped_events: 0",
                 "events <",
                 "  time_ms: 1",
+                "  transport: 0",
                 "  validation_probe_event <",
                 "    latency_ms: 40730",
                 "    network_id <",
@@ -261,6 +274,7 @@
         verifySerialization(want, ev);
     }
 
+    @SmallTest
     public void testApfProgramEventSerialization() {
         ConnectivityMetricsEvent ev = describeIpEvent(
                 aType(ApfProgramEvent.class),
@@ -273,6 +287,8 @@
         String want = joinLines(
                 "dropped_events: 0",
                 "events <",
+                "  time_ms: 1",
+                "  transport: 0",
                 "  apf_program_event <",
                 "    current_ras: 9",
                 "    drop_multicast: true",
@@ -281,13 +297,13 @@
                 "    lifetime: 200",
                 "    program_length: 2048",
                 "  >",
-                "  time_ms: 1",
                 ">",
                 "version: 2");
 
         verifySerialization(want, ev);
     }
 
+    @SmallTest
     public void testApfStatsSerialization() {
         ConnectivityMetricsEvent ev = describeIpEvent(
                 aType(ApfStats.class),
@@ -303,6 +319,8 @@
         String want = joinLines(
                 "dropped_events: 0",
                 "events <",
+                "  time_ms: 1",
+                "  transport: 0",
                 "  apf_statistics <",
                 "    dropped_ras: 2",
                 "    duration_ms: 45000",
@@ -313,13 +331,13 @@
                 "    received_ras: 10",
                 "    zero_lifetime_ras: 1",
                 "  >",
-                "  time_ms: 1",
                 ">",
                 "version: 2");
 
         verifySerialization(want, ev);
     }
 
+    @SmallTest
     public void testRaEventSerialization() {
         ConnectivityMetricsEvent ev = describeIpEvent(
                 aType(RaEvent.class),
@@ -333,6 +351,8 @@
         String want = joinLines(
                 "dropped_events: 0",
                 "events <",
+                "  time_ms: 1",
+                "  transport: 0",
                 "  ra_event <",
                 "    dnssl_lifetime: -1",
                 "    prefix_preferred_lifetime: 300",
@@ -341,7 +361,6 @@
                 "    route_info_lifetime: -1",
                 "    router_lifetime: 2000",
                 "  >",
-                "  time_ms: 1",
                 ">",
                 "version: 2");
 
@@ -350,7 +369,8 @@
 
     static void verifySerialization(String want, ConnectivityMetricsEvent... input) {
         try {
-            byte[] got = IpConnectivityEventBuilder.serialize(0, Arrays.asList(input));
+            byte[] got = IpConnectivityEventBuilder.serialize(0,
+                    IpConnectivityEventBuilder.toProto(Arrays.asList(input)));
             IpConnectivityLog log = IpConnectivityLog.parseFrom(got);
             assertEquals(want, log.toString());
         } catch (Exception e) {
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index 78d16d9..e9257fa 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -32,22 +32,19 @@
 import android.net.metrics.RaEvent;
 import android.net.metrics.ValidationProbeEvent;
 import android.os.Parcelable;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Base64;
-
 import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass;
-
-import junit.framework.TestCase;
-
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
 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;
 
 public class IpConnectivityMetricsTest extends TestCase {
     static final IpReachabilityEvent FAKE_EV =
@@ -63,6 +60,7 @@
         mService = new IpConnectivityMetrics(mCtx, (ctx) -> 2000);
     }
 
+    @SmallTest
     public void testLoggingEvents() throws Exception {
         IpConnectivityLog logger = new IpConnectivityLog(mMockService);
 
@@ -76,6 +74,7 @@
         assertEventsEqual(expectedEvent(3), got.get(2));
     }
 
+    @SmallTest
     public void testLoggingEventsWithMultipleCallers() throws Exception {
         IpConnectivityLog logger = new IpConnectivityLog(mMockService);
 
@@ -103,6 +102,7 @@
         }
     }
 
+    @SmallTest
     public void testBufferFlushing() {
         String output1 = getdump("flush");
         assertEquals("", output1);
@@ -115,6 +115,7 @@
         assertEquals("", output3);
     }
 
+    @SmallTest
     public void testRateLimiting() {
         final IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
         final ApfProgramEvent ev = new ApfProgramEvent(0, 0, 0, 0, 0);
@@ -136,6 +137,7 @@
         assertEquals("", output2);
     }
 
+    @SmallTest
     public void testEndToEndLogging() {
         IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
 
@@ -156,22 +158,25 @@
         String want = joinLines(
                 "dropped_events: 0",
                 "events <",
+                "  time_ms: 100",
+                "  transport: 0",
                 "  ip_reachability_event <",
                 "    event_type: 512",
                 "    if_name: \"wlan0\"",
                 "  >",
-                "  time_ms: 100",
                 ">",
                 "events <",
+                "  time_ms: 200",
+                "  transport: 0",
                 "  dhcp_event <",
                 "    duration_ms: 192",
-                "    error_code: 0",
                 "    if_name: \"wlan0\"",
                 "    state_transition: \"SomeState\"",
                 "  >",
-                "  time_ms: 200",
                 ">",
                 "events <",
+                "  time_ms: 300",
+                "  transport: 0",
                 "  default_network_event <",
                 "    network_id <",
                 "      network_id: 102",
@@ -184,18 +189,19 @@
                 "    transport_types: 2",
                 "    transport_types: 3",
                 "  >",
-                "  time_ms: 300",
                 ">",
                 "events <",
+                "  time_ms: 400",
+                "  transport: 0",
                 "  ip_provisioning_event <",
                 "    event_type: 1",
                 "    if_name: \"wlan0\"",
                 "    latency_ms: 5678",
                 "  >",
-                "  time_ms: 400",
                 ">",
                 "events <",
                 "  time_ms: 500",
+                "  transport: 0",
                 "  validation_probe_event <",
                 "    latency_ms: 40730",
                 "    network_id <",
@@ -206,6 +212,8 @@
                 "  >",
                 ">",
                 "events <",
+                "  time_ms: 600",
+                "  transport: 0",
                 "  apf_statistics <",
                 "    dropped_ras: 2",
                 "    duration_ms: 45000",
@@ -216,9 +224,10 @@
                 "    received_ras: 10",
                 "    zero_lifetime_ras: 1",
                 "  >",
-                "  time_ms: 600",
                 ">",
                 "events <",
+                "  time_ms: 700",
+                "  transport: 0",
                 "  ra_event <",
                 "    dnssl_lifetime: -1",
                 "    prefix_preferred_lifetime: 300",
@@ -227,7 +236,6 @@
                 "    route_info_lifetime: -1",
                 "    router_lifetime: 2000",
                 "  >",
-                "  time_ms: 700",
                 ">",
                 "version: 2");
 
@@ -284,10 +292,5 @@
     }
 
     static final Comparator<ConnectivityMetricsEvent> EVENT_COMPARATOR =
-        new Comparator<ConnectivityMetricsEvent>() {
-            @Override
-            public int compare(ConnectivityMetricsEvent ev1, ConnectivityMetricsEvent ev2) {
-                return (int) (ev1.timestamp - ev2.timestamp);
-            }
-        };
+        Comparator.comparingLong((ev) -> ev.timestamp);
 }
diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
index 2bb62bb..75d2f1a 100644
--- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
@@ -16,25 +16,35 @@
 
 package com.android.server.connectivity;
 
-import android.net.ConnectivityManager.NetworkCallback;
 import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
 import android.net.Network;
+import android.net.metrics.ConnectStats;
 import android.net.metrics.DnsEvent;
 import android.net.metrics.INetdEventListener;
 import android.net.metrics.IpConnectivityLog;
 import android.os.RemoteException;
+import android.system.OsConstants;
 import android.test.suitebuilder.annotation.SmallTest;
-
+import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.OptionalInt;
+import java.util.stream.IntStream;
 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.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.eq;
@@ -42,13 +52,6 @@
 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
@@ -68,45 +71,48 @@
         }
     }
 
+    private static final String EXAMPLE_IPV4 = "192.0.2.1";
+    private static final String EXAMPLE_IPV6 = "2001:db8:1200::2:1";
+
     NetdEventListenerService mNetdEventListenerService;
 
     @Mock ConnectivityManager mCm;
     @Mock IpConnectivityLog mLog;
     ArgumentCaptor<NetworkCallback> mCallbackCaptor;
-    ArgumentCaptor<DnsEvent> mEvCaptor;
+    ArgumentCaptor<DnsEvent> mDnsEvCaptor;
 
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mCallbackCaptor = ArgumentCaptor.forClass(NetworkCallback.class);
-        mEvCaptor = ArgumentCaptor.forClass(DnsEvent.class);
+        mDnsEvCaptor = ArgumentCaptor.forClass(DnsEvent.class);
         mNetdEventListenerService = new NetdEventListenerService(mCm, mLog);
 
         verify(mCm, times(1)).registerNetworkCallback(any(), mCallbackCaptor.capture());
     }
 
     @SmallTest
-    public void testOneBatch() throws Exception {
+    public void testOneDnsBatch() 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));
+        verifyLoggedDnsEvents(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(
+        mDnsEvCaptor = ArgumentCaptor.forClass(DnsEvent.class); // reset argument captor
+        verifyLoggedDnsEvents(
             new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
             new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES));
     }
 
     @SmallTest
-    public void testSeveralBatches() throws Exception {
+    public void testSeveralDmsBatches() throws Exception {
         log(105, LATENCIES);
         log(106, LATENCIES);
         log(105, LATENCIES);
         log(107, LATENCIES);
 
-        verifyLoggedEvents(
+        verifyLoggedDnsEvents(
             new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
             new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES),
             new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
@@ -114,7 +120,7 @@
     }
 
     @SmallTest
-    public void testBatchAndNetworkLost() throws Exception {
+    public void testDnsBatchAndNetworkLost() throws Exception {
         byte[] eventTypes = Arrays.copyOf(EVENT_TYPES, 20);
         byte[] returnCodes = Arrays.copyOf(RETURN_CODES, 20);
         int[] latencies = Arrays.copyOf(LATENCIES, 20);
@@ -124,14 +130,14 @@
         mCallbackCaptor.getValue().onLost(new Network(105));
         log(105, LATENCIES);
 
-        verifyLoggedEvents(
+        verifyLoggedDnsEvents(
             new DnsEvent(105, eventTypes, returnCodes, latencies),
             new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
             new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES));
     }
 
     @SmallTest
-    public void testConcurrentBatchesAndDumps() throws Exception {
+    public void testConcurrentDnsBatchesAndDumps() throws Exception {
         final long stop = System.currentTimeMillis() + 100;
         final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null"));
         new Thread() {
@@ -142,27 +148,121 @@
             }
         }.start();
 
-        logAsync(105, LATENCIES);
-        logAsync(106, LATENCIES);
-        logAsync(107, LATENCIES);
+        logDnsAsync(105, LATENCIES);
+        logDnsAsync(106, LATENCIES);
+        logDnsAsync(107, LATENCIES);
 
-        verifyLoggedEvents(500,
+        verifyLoggedDnsEvents(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));
     }
 
     @SmallTest
-    public void testConcurrentBatchesAndNetworkLoss() throws Exception {
-        logAsync(105, LATENCIES);
+    public void testConcurrentDnsBatchesAndNetworkLoss() throws Exception {
+        logDnsAsync(105, LATENCIES);
         Thread.sleep(10L);
-        // call onLost() asynchronously to logAsync's onDnsEvent() calls.
+        // call onLost() asynchronously to logDnsAsync's onDnsEvent() calls.
         mCallbackCaptor.getValue().onLost(new Network(105));
 
         // do not verify unpredictable batch
         verify(mLog, timeout(500).times(1)).log(any());
     }
 
+    @SmallTest
+    public void testConnectLogging() throws Exception {
+        final int OK = 0;
+        Thread[] logActions = {
+            // ignored
+            connectEventAction(OsConstants.EALREADY, 0, EXAMPLE_IPV4),
+            connectEventAction(OsConstants.EALREADY, 0, EXAMPLE_IPV6),
+            connectEventAction(OsConstants.EINPROGRESS, 0, EXAMPLE_IPV4),
+            connectEventAction(OsConstants.EINPROGRESS, 0, EXAMPLE_IPV6),
+            connectEventAction(OsConstants.EINPROGRESS, 0, EXAMPLE_IPV6),
+            // valid latencies
+            connectEventAction(OK, 110, EXAMPLE_IPV4),
+            connectEventAction(OK, 23, EXAMPLE_IPV4),
+            connectEventAction(OK, 45, EXAMPLE_IPV4),
+            connectEventAction(OK, 56, EXAMPLE_IPV4),
+            connectEventAction(OK, 523, EXAMPLE_IPV6),
+            connectEventAction(OK, 214, EXAMPLE_IPV6),
+            connectEventAction(OK, 67, EXAMPLE_IPV6),
+            // errors
+            connectEventAction(OsConstants.EPERM, 0, EXAMPLE_IPV4),
+            connectEventAction(OsConstants.EPERM, 0, EXAMPLE_IPV4),
+            connectEventAction(OsConstants.EAGAIN, 0, EXAMPLE_IPV4),
+            connectEventAction(OsConstants.EACCES, 0, EXAMPLE_IPV4),
+            connectEventAction(OsConstants.EACCES, 0, EXAMPLE_IPV4),
+            connectEventAction(OsConstants.EACCES, 0, EXAMPLE_IPV6),
+            connectEventAction(OsConstants.EADDRINUSE, 0, EXAMPLE_IPV4),
+            connectEventAction(OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV4),
+            connectEventAction(OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV6),
+            connectEventAction(OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV6),
+            connectEventAction(OsConstants.ECONNREFUSED, 0, EXAMPLE_IPV4),
+        };
+
+        for (Thread t : logActions) {
+            t.start();
+        }
+        for (Thread t : logActions) {
+            t.join();
+        }
+
+        List<IpConnectivityEvent> events = new ArrayList<>();
+        mNetdEventListenerService.flushStatistics(events);
+
+        IpConnectivityEvent got = events.get(0);
+        String want = String.join("\n",
+                "time_ms: 0",
+                "transport: 0",
+                "connect_statistics <",
+                "  connect_count: 12",
+                "  errnos_counters <",
+                "    key: 1",
+                "    value: 2",
+                "  >",
+                "  errnos_counters <",
+                "    key: 11",
+                "    value: 1",
+                "  >",
+                "  errnos_counters <",
+                "    key: 13",
+                "    value: 3",
+                "  >",
+                "  errnos_counters <",
+                "    key: 98",
+                "    value: 1",
+                "  >",
+                "  errnos_counters <",
+                "    key: 110",
+                "    value: 3",
+                "  >",
+                "  errnos_counters <",
+                "    key: 111",
+                "    value: 1",
+                "  >",
+                "  ipv6_addr_count: 6",
+                "  latencies_ms: 23",
+                "  latencies_ms: 45",
+                "  latencies_ms: 56",
+                "  latencies_ms: 67",
+                "  latencies_ms: 110",
+                "  latencies_ms: 214",
+                "  latencies_ms: 523",
+                ">\n");
+        verifyConnectEvent(want, got);
+    }
+
+    Thread connectEventAction(int error, int latencyMs, String ipAddr) {
+        return new Thread(() -> {
+            try {
+                mNetdEventListenerService.onConnectEvent(100, error, latencyMs, ipAddr, 80, 1);
+            } catch (Exception e) {
+                fail(e.toString());
+            }
+        });
+    }
+
     void log(int netId, int[] latencies) {
         try {
             for (int l : latencies) {
@@ -174,7 +274,7 @@
         }
     }
 
-    void logAsync(int netId, int[] latencies) {
+    void logDnsAsync(int netId, int[] latencies) {
         new Thread() {
             public void run() {
                 log(netId, latencies);
@@ -182,15 +282,15 @@
         }.start();
     }
 
-    void verifyLoggedEvents(DnsEvent... expected) {
-        verifyLoggedEvents(0, expected);
+    void verifyLoggedDnsEvents(DnsEvent... expected) {
+        verifyLoggedDnsEvents(0, expected);
     }
 
-    void verifyLoggedEvents(int wait, DnsEvent... expectedEvents) {
-        verify(mLog, timeout(wait).times(expectedEvents.length)).log(mEvCaptor.capture());
-        for (DnsEvent got : mEvCaptor.getAllValues()) {
+    void verifyLoggedDnsEvents(int wait, DnsEvent... expectedEvents) {
+        verify(mLog, timeout(wait).times(expectedEvents.length)).log(mDnsEvCaptor.capture());
+        for (DnsEvent got : mDnsEvCaptor.getAllValues()) {
             OptionalInt index = IntStream.range(0, expectedEvents.length)
-                    .filter(i -> eventsEqual(expectedEvents[i], got))
+                    .filter(i -> dnsEventsEqual(expectedEvents[i], got))
                     .findFirst();
             // Don't match same expected event more than once.
             index.ifPresent(i -> expectedEvents[i] = null);
@@ -199,11 +299,22 @@
     }
 
     /** equality function for DnsEvent to avoid overriding equals() and hashCode(). */
-    static boolean eventsEqual(DnsEvent expected, DnsEvent got) {
+    static boolean dnsEventsEqual(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));
     }
+
+    static void verifyConnectEvent(String expected, IpConnectivityEvent got) {
+        try {
+            Arrays.sort(got.getConnectStatistics().latenciesMs);
+            Arrays.sort(got.getConnectStatistics().errnosCounters,
+                    Comparator.comparingInt((p) -> p.key));
+            assertEquals(expected, got.toString());
+        } catch (Exception e) {
+            fail(e.toString());
+        }
+    }
 }
diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
new file mode 100644
index 0000000..98073ce
--- /dev/null
+++ b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -0,0 +1,141 @@
+/*
+ * 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.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.telephony.TelephonyManager;
+import android.test.suitebuilder.annotation.SmallTest;
+import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import junit.framework.TestCase;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.*;
+import static org.mockito.Mockito.any;
+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;
+
+public class NetworkNotificationManagerTest extends TestCase {
+
+    static final NetworkCapabilities CELL_CAPABILITIES = new NetworkCapabilities();
+    static final NetworkCapabilities WIFI_CAPABILITIES = new NetworkCapabilities();
+    static {
+        CELL_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+        CELL_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+
+        WIFI_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
+        WIFI_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+    }
+
+    @Mock Context mCtx;
+    @Mock Resources mResources;
+    @Mock PackageManager mPm;
+    @Mock TelephonyManager mTelephonyManager;
+    @Mock NotificationManager mNotificationManager;
+    @Mock NetworkAgentInfo mWifiNai;
+    @Mock NetworkAgentInfo mCellNai;
+    @Mock NetworkInfo mNetworkInfo;
+    ArgumentCaptor<Notification> mCaptor;
+
+    NetworkNotificationManager mManager;
+
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mCaptor = ArgumentCaptor.forClass(Notification.class);
+        mWifiNai.networkCapabilities = WIFI_CAPABILITIES;
+        mWifiNai.networkInfo = mNetworkInfo;
+        mCellNai.networkCapabilities = CELL_CAPABILITIES;
+        mCellNai.networkInfo = mNetworkInfo;
+        when(mCtx.getResources()).thenReturn(mResources);
+        when(mCtx.getPackageManager()).thenReturn(mPm);
+        when(mCtx.getApplicationInfo()).thenReturn(new ApplicationInfo());
+        when(mResources.getColor(anyInt(), any())).thenReturn(0xFF607D8B);
+
+        mManager = new NetworkNotificationManager(mCtx, mTelephonyManager, mNotificationManager);
+    }
+
+    @SmallTest
+    public void testNotificationsShownAndCleared() {
+        final int NETWORK_ID_BASE = 100;
+        List<NotificationType> types = Arrays.asList(NotificationType.values());
+        List<Integer> ids = new ArrayList<>(types.size());
+        for (int i = 0; i < ids.size(); i++) {
+            ids.add(NETWORK_ID_BASE + i);
+        }
+        Collections.shuffle(ids);
+        Collections.shuffle(types);
+
+        for (int i = 0; i < ids.size(); i++) {
+            mManager.showNotification(ids.get(i), types.get(i), mWifiNai, mCellNai, null, false);
+        }
+
+        Collections.shuffle(ids);
+        for (int i = 0; i < ids.size(); i++) {
+            mManager.clearNotification(ids.get(i));
+        }
+
+        for (int i = 0; i < ids.size(); i++) {
+            final int id = ids.get(i);
+            final int eventId = types.get(i).eventId;
+            final String tag = NetworkNotificationManager.tagFor(id);
+            verify(mNotificationManager, times(1)).notifyAsUser(eq(tag), eq(eventId), any(), any());
+            verify(mNotificationManager, times(1)).cancelAsUser(eq(tag), eq(eventId), any());
+        }
+    }
+
+    @SmallTest
+    public void testNoInternetNotificationsNotShownForCellular() {
+        mManager.showNotification(100, NO_INTERNET, mCellNai, mWifiNai, null, false);
+        mManager.showNotification(101, LOST_INTERNET, mCellNai, mWifiNai, null, false);
+
+        verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any());
+
+        mManager.showNotification(102, NO_INTERNET, mWifiNai, mCellNai, null, false);
+
+        final int eventId = NO_INTERNET.eventId;
+        final String tag = NetworkNotificationManager.tagFor(102);
+        verify(mNotificationManager, times(1)).notifyAsUser(eq(tag), eq(eventId), any(), any());
+    }
+
+    @SmallTest
+    public void testNotificationsNotShownIfNoInternetCapability() {
+        mWifiNai.networkCapabilities = new NetworkCapabilities();
+        mWifiNai.networkCapabilities .addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
+        mManager.showNotification(102, NO_INTERNET, mWifiNai, mCellNai, null, false);
+        mManager.showNotification(103, LOST_INTERNET, mWifiNai, mCellNai, null, false);
+        mManager.showNotification(104, NETWORK_SWITCH, mWifiNai, mCellNai, null, false);
+
+        verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any());
+    }
+}
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 7d6f32b..28a2cb3 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -93,8 +93,7 @@
         }
 
         try {
-            mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false, false, null,
-                    Configuration.EMPTY, 0, false, false, 0, -1, false);
+            mWm.addAppToken(0, null, 0, 0, false, false, 0, false, false, false, 0, -1);
             fail("IWindowManager.addAppToken did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {
@@ -104,7 +103,7 @@
         }
 
         try {
-            mWm.setAppTask(null, 0, INVALID_STACK_ID, null, null, 0, false, false);
+            mWm.addAppToTask(null, 0);
             fail("IWindowManager.setAppGroupId did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {
diff --git a/tools/incident_report/Android.mk b/tools/incident_report/Android.mk
new file mode 100644
index 0000000..ed89bd6
--- /dev/null
+++ b/tools/incident_report/Android.mk
@@ -0,0 +1,39 @@
+#
+# 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.
+#
+LOCAL_PATH:= $(call my-dir)
+
+# ==========================================================
+# Build the host executable: protoc-gen-javastream
+# ==========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := incident_report
+
+LOCAL_C_INCLUDES := \
+    external/protobuf/src
+
+LOCAL_SRC_FILES := \
+    generic_message.cpp \
+    main.cpp \
+    printer.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libplatformprotos \
+    libprotobuf-cpp-full
+
+include $(BUILD_HOST_EXECUTABLE)
+
+
diff --git a/tools/incident_report/formatter.cpp b/tools/incident_report/formatter.cpp
new file mode 100644
index 0000000..944348f
--- /dev/null
+++ b/tools/incident_report/formatter.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 "proto_format.h"
+
+#include <string.h>
+
+extern int const PROTO_FORMAT_STRING_POOL_SIZE;
+extern int const PROTO_FORMAT_ENUM_LABELS_LENGTH;
+extern int const PROTO_FORMAT_MESSAGES_LENGTH;
+extern int const PROTO_FORMAT_FIELDS_LENGTH;
+
+extern char const PROTO_FORMAT_STRING_POOL[];
+extern ProtoFieldFormat const PROTO_FORMAT_FIELDS[];
+extern ProtoEnumLabel const PROTO_FORMAT_ENUM_LABELS[];
+extern ProtoMessageFormat const PROTO_FORMAT_MESSAGES[];
+
+static const char*
+get_string(int index)
+{
+    if (index >= 0 && index < PROTO_FORMAT_STRING_POOL_SIZE) {
+        return PROTO_FORMAT_STRING_POOL + index;
+    } else {
+        // These indices all come from within the generated table, so just crash now.
+        *(int*)NULL = 42;
+        return NULL;
+    }
+}
+
+static ProtoMessageFormat const*
+get_message(int index)
+{
+    if (index >= 0 && index < PROTO_FORMAT_MESSAGES_LENGTH) {
+        return PROTO_FORMAT_MESSAGES + index;
+    } else {
+        // These indices all come from within the generated table, so just crash now.
+        *(int*)NULL = 42;
+        return NULL;
+    }
+}
+
+static int
+compare_name(const char* full, const char* package, const char* clazz)
+{
+    int const packageLen = strlen(package);
+    int cmp = strncmp(full, package, packageLen);
+    if (cmp == 0) {
+        cmp = full[packageLen] - '.';
+        if (cmp == 0) {
+            return strcmp(full + packageLen, clazz);
+        }
+    }
+    return cmp;
+}
+
+int
+find_message_index(const char* name)
+{
+    size_t low = 0;
+    size_t high = PROTO_FORMAT_FIELDS_LENGTH - 1;
+
+    while (low <= high) {
+        size_t mid = (low + high) >> 1;
+        ProtoMessageFormat const* msg = get_message(mid);
+
+        int cmp = compare_name(name, get_string(msg->package_name), get_string(msg->package_name));
+        if (cmp < 0) {
+            low = mid + 1;
+        } else if (cmp > 0) {
+            high = mid - 1;
+        } else {
+            return mid;
+        }
+    }
+    return -1;
+}
diff --git a/tools/incident_report/generic_message.cpp b/tools/incident_report/generic_message.cpp
new file mode 100644
index 0000000..84d9d7c
--- /dev/null
+++ b/tools/incident_report/generic_message.cpp
@@ -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.
+ */
+
+#include "generic_message.h"
+
+GenericMessage::GenericMessage()
+{
+}
+
+GenericMessage::~GenericMessage()
+{
+}
+
+void
+GenericMessage::addInt32(int32_t fieldId, uint32_t value)
+{
+    Node node;
+    node.type = TYPE_VALUE32;
+    node.value32 = value;
+    mNodes.insert(pair<int32_t,Node>(fieldId, node));
+}
+
+void
+GenericMessage::addInt64(int32_t fieldId, uint64_t value)
+{
+    Node node;
+    node.type = TYPE_VALUE64;
+    node.value64 = value;
+    mNodes.insert(pair<int32_t,Node>(fieldId, node));
+}
+
+GenericMessage*
+GenericMessage::addMessage(int32_t fieldId)
+{
+    GenericMessage* result = new GenericMessage();
+    Node node;
+    node.type = TYPE_MESSAGE;
+    node.message = result;
+    mNodes.insert(pair<int32_t,Node>(fieldId, node));
+    return result;
+}
+
+void
+GenericMessage::addString(int32_t fieldId, const string& value)
+{
+    Node node;
+    node.type = TYPE_STRING;
+    node.str = new string(value);
+    mNodes.insert(pair<int32_t,Node>(fieldId, node));
+}
+
+GenericMessage::const_iterator_pair
+GenericMessage::find(int fieldId) const
+{
+    return mNodes.equal_range(fieldId);
+}
+
diff --git a/tools/incident_report/generic_message.h b/tools/incident_report/generic_message.h
new file mode 100644
index 0000000..df3f7b2
--- /dev/null
+++ b/tools/incident_report/generic_message.h
@@ -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.
+ */
+
+#ifndef GENERIC_MESSAGE_H
+#define GENERIC_MESSAGE_H
+
+#include <map>
+#include <string>
+
+using namespace std;
+
+/**
+ * Class to represent a protobuf Message, where we don't actually
+ * know what any of the fields are, just their type codes. In other
+ * words, this loslessly stores a parsed protobuf object without
+ * having the .proto file that generated it.
+ */
+class GenericMessage
+{
+public:
+    GenericMessage();
+    ~GenericMessage();
+
+    enum {
+        TYPE_VALUE32,
+        TYPE_VALUE64,
+        TYPE_MESSAGE,
+        TYPE_STRING,
+        TYPE_DATA
+    };
+
+    struct Node {
+        uint32_t type;
+        union {
+            uint32_t value32;
+            uint64_t value64;
+            GenericMessage* message;
+            string* str;
+            string* data;
+        };
+    };
+
+    void addInt32(int32_t fieldId, uint32_t value);
+    void addInt64(int32_t fieldId, uint64_t value);
+    GenericMessage* addMessage(int32_t fieldId);
+    void addString(int32_t fieldId, const string& value);
+
+    typedef multimap<int32_t,Node>::const_iterator const_iterator;
+    typedef pair<const_iterator,const_iterator> const_iterator_pair;
+
+    const_iterator_pair find(int fieldId) const;
+
+private:
+    multimap<int,Node> mNodes;
+};
+
+#endif // GENERIC_MESSAGE_H
+
diff --git a/tools/incident_report/main.cpp b/tools/incident_report/main.cpp
new file mode 100644
index 0000000..a814847
--- /dev/null
+++ b/tools/incident_report/main.cpp
@@ -0,0 +1,576 @@
+/*
+ * 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 "generic_message.h"
+#include "printer.h"
+
+#include <frameworks/base/core/proto/android/os/incident_proto.pb.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+using namespace android::os;
+using namespace google::protobuf;
+using namespace google::protobuf::io;
+using namespace google::protobuf::internal;
+
+static bool read_message(CodedInputStream* in, Descriptor const* descriptor,
+        GenericMessage* message);
+static void print_message(Out* out, Descriptor const* descriptor, GenericMessage const* message);
+
+// ================================================================================
+static bool
+read_length_delimited(CodedInputStream* in, uint32 fieldId, Descriptor const* descriptor,
+        GenericMessage* message)
+{
+    uint32 size;
+    if (!in->ReadVarint32(&size)) {
+        return false;
+    }
+
+    FieldDescriptor const* field = descriptor->FindFieldByNumber(fieldId);
+    if (field != NULL) {
+        int type = field->type();
+        if (type == FieldDescriptor::TYPE_MESSAGE) {
+            GenericMessage* child = message->addMessage(fieldId);
+
+            CodedInputStream::Limit limit = in->PushLimit(size);
+            bool rv = read_message(in, field->message_type(), child);
+            in->PopLimit(limit);
+            return rv;
+        } else if (type == FieldDescriptor::TYPE_STRING) {
+            // TODO: do a version of readstring that just pumps the data
+            // rather than allocating a string which we don't care about.
+            string str;
+            if (in->ReadString(&str, size)) {
+                message->addString(fieldId, str);
+                return true;
+            } else {
+                return false;
+            }
+        } else if (type == FieldDescriptor::TYPE_BYTES) {
+            // TODO: Save bytes field.
+            return in->Skip(size);
+        }
+    }
+    return in->Skip(size);
+}
+
+// ================================================================================
+static bool
+read_message(CodedInputStream* in, Descriptor const* descriptor, GenericMessage* message)
+{
+    uint32 value32;
+    uint64 value64;
+
+    while (true) {
+        uint32 tag = in->ReadTag();
+        if (tag == 0) {
+            return true;
+        }
+        int fieldId = WireFormatLite::GetTagFieldNumber(tag);
+        switch (WireFormatLite::GetTagWireType(tag)) {
+            case WireFormatLite::WIRETYPE_VARINT:
+                if (in->ReadVarint64(&value64)) {
+                    message->addInt64(fieldId, value64);
+                    break;
+                } else {
+                    return false;
+                }
+            case WireFormatLite::WIRETYPE_FIXED64:
+                if (in->ReadLittleEndian64(&value64)) {
+                    message->addInt64(fieldId, value64);
+                    break;
+                } else {
+                    return false;
+                }
+            case WireFormatLite::WIRETYPE_LENGTH_DELIMITED:
+                if (!read_length_delimited(in, fieldId, descriptor, message)) {
+                    return false;
+                }
+                break;
+            case WireFormatLite::WIRETYPE_FIXED32:
+                if (in->ReadLittleEndian32(&value32)) {
+                    message->addInt32(fieldId, value32);
+                    break;
+                } else {
+                    return false;
+                }
+            default:
+                fprintf(stderr, "bad tag: 0x%x (%d) at index %d\n", tag, tag,
+                        in->CurrentPosition());
+                return false;
+        }
+    }
+}
+
+// ================================================================================
+static void
+print_value(Out* out, FieldDescriptor const* field, GenericMessage::Node const& node)
+{
+    uint32_t val32;
+    FieldDescriptor::Type type = field->type();
+
+    switch (node.type) {
+        case GenericMessage::TYPE_VALUE32:
+            switch (type) {
+                case FieldDescriptor::TYPE_FIXED32:
+                    out->printf("%u", node.value32);
+                    break;
+                case FieldDescriptor::TYPE_SFIXED32:
+                    out->printf("%d", node.value32);
+                    break;
+                case FieldDescriptor::TYPE_FLOAT:
+                    out->printf("%f", *(float*)&node.value32);
+                    break;
+                default:
+                    out->printf("(unexpected value %d (0x%x)", node.value32, node.value32);
+                    break;
+            }
+            break;
+        case GenericMessage::TYPE_VALUE64:
+            switch (type) {
+                case FieldDescriptor::TYPE_FIXED64:
+                case FieldDescriptor::TYPE_SFIXED64:
+                case FieldDescriptor::TYPE_DOUBLE:
+                    out->printf("%f", *(double*)&node.value64);
+                    break;
+                case FieldDescriptor::TYPE_SINT32:
+                case FieldDescriptor::TYPE_INT32:
+                    val32 = (uint32_t)node.value32;
+                    out->printf("%d", val32);
+                    break;
+                case FieldDescriptor::TYPE_INT64:
+                case FieldDescriptor::TYPE_UINT32:
+                    val32 = (uint32_t)node.value32;
+                    out->printf("%u", val32);
+                    break;
+                case FieldDescriptor::TYPE_UINT64:
+                case FieldDescriptor::TYPE_SINT64:
+                case FieldDescriptor::TYPE_BOOL:
+                    if (node.value64) {
+                        out->printf("true");
+                    } else {
+                        out->printf("false");
+                    }
+                    break;
+                case FieldDescriptor::TYPE_ENUM:
+                default:
+                    out->printf("(unexpected value %ld (0x%x))", node.value64, node.value64);
+                    break;
+            }
+            break;
+        case GenericMessage::TYPE_MESSAGE:
+            print_message(out, field->message_type(), node.message);
+            break;
+        case GenericMessage::TYPE_STRING:
+            // TODO: custom format for multi-line strings.
+            out->printf("%s", node.str->c_str());
+            break;
+        case GenericMessage::TYPE_DATA:
+            out->printf("<bytes>");
+            break;
+    }
+}
+
+static void
+print_message(Out* out, Descriptor const* descriptor, GenericMessage const* message)
+{
+    out->printf("%s {\n", descriptor->name().c_str());
+    out->indent();
+
+    int const N = descriptor->field_count();
+    for (int i=0; i<N; i++) {
+        FieldDescriptor const* field = descriptor->field(i);
+
+        int fieldId = field->number();
+        bool repeated = field->label() == FieldDescriptor::LABEL_REPEATED;
+        FieldDescriptor::Type type = field->type();
+        GenericMessage::const_iterator_pair it = message->find(fieldId);
+
+        out->printf("%s=", field->name().c_str());
+        if (repeated) {
+            if (it.first != it.second) {
+                out->printf("[");
+                if (type == FieldDescriptor::TYPE_MESSAGE
+                        || type == FieldDescriptor::TYPE_STRING
+                        || type == FieldDescriptor::TYPE_BYTES) {
+                    out->printf("\n");
+                }
+                out->indent();
+
+                for (GenericMessage::const_iterator_pair it = message->find(fieldId);
+                        it.first != it.second; it.first++) {
+                    print_value(out, field, it.first->second);
+                    if (type == FieldDescriptor::TYPE_MESSAGE
+                            || type == FieldDescriptor::TYPE_STRING
+                            || type == FieldDescriptor::TYPE_BYTES) {
+                        out->printf("\n");
+                    }
+                }
+
+                out->dedent();
+                out->printf("]");
+            } else {
+                out->printf("[]");
+            }
+        } else {
+            if (it.first != it.second) {
+                print_value(out, field, it.first->second);
+            } else {
+                switch (type) {
+                    case FieldDescriptor::TYPE_BOOL:
+                        out->printf("false");
+                        break;
+                    case FieldDescriptor::TYPE_STRING:
+                    case FieldDescriptor::TYPE_MESSAGE:
+                        out->printf("");
+                        break;
+                    case FieldDescriptor::TYPE_ENUM:
+                        out->printf("%s", field->default_value_enum()->name().c_str());
+                        break;
+                    default:
+                        out->printf("0");
+                        break;
+                }
+            }
+        }
+        out->printf("\n");
+    }
+    out->dedent();
+    out->printf("}");
+}
+
+// ================================================================================
+static uint8_t*
+write_raw_varint(uint8_t* buf, uint32_t val)
+{
+    uint8_t* p = buf;
+    while (true) {
+        if ((val & ~0x7F) == 0) {
+            *p++ = (uint8_t)val;
+            return p;
+        } else {
+            *p++ = (uint8_t)((val & 0x7F) | 0x80);
+            val >>= 7;
+        }
+    }
+}
+
+static int
+write_all(int fd, uint8_t const* buf, size_t size)
+{
+    while (size > 0) {
+        ssize_t amt = ::write(fd, buf, size);
+        if (amt < 0) {
+            return errno;
+        }
+        size -= amt;
+        buf += amt;
+    }
+    return 0;
+}
+
+static int
+adb_incident_workaround(const char* adbSerial, const vector<string>& sections)
+{
+    const int maxAllowedSize = 20 * 1024 * 1024; // 20MB
+    uint8_t* buffer = (uint8_t*)malloc(maxAllowedSize);
+
+    for (vector<string>::const_iterator it=sections.begin(); it!=sections.end(); it++) {
+        Descriptor const* descriptor = IncidentProto::descriptor();
+        FieldDescriptor const* field;
+
+        // Get the name and field id.
+        string name = *it;
+        char* end;
+        int id = strtol(name.c_str(), &end, 0);
+        if (*end == '\0') {
+            // If it's an id, find out the string.
+            field = descriptor->FindFieldByNumber(id);
+            if (field == NULL) {
+                fprintf(stderr, "Unable to find field number: %d\n", id);
+                return 1;
+            }
+            name = field->name();
+        } else {
+            // If it's a string, find out the id.
+            field = descriptor->FindFieldByName(name);
+            if (field == NULL) {
+                fprintf(stderr, "Unable to find field: %s\n", name.c_str());
+                return 1;
+            }
+            id = field->number();
+        }
+        
+        int pfd[2];
+        if (pipe(pfd) != 0) {
+            fprintf(stderr, "pipe failed: %s\n", strerror(errno));
+            return 1;
+        }
+
+        pid_t pid = fork();
+        if (pid == -1) {
+            fprintf(stderr, "fork failed: %s\n", strerror(errno));
+            return 1;
+        } else if (pid == 0) {
+            // child
+            dup2(pfd[1], STDOUT_FILENO);
+            close(pfd[0]);
+            close(pfd[1]);
+
+            char const** args = (char const**)malloc(sizeof(char*) * 8);
+            int argpos = 0;
+            args[argpos++] = "adb";
+            if (adbSerial != NULL) {
+                args[argpos++] = "-s";
+                args[argpos++] = adbSerial;
+            }
+            args[argpos++] = "shell";
+            args[argpos++] = "dumpsys";
+            args[argpos++] = name.c_str();
+            args[argpos++] = "--proto";
+            args[argpos++] = NULL;
+            execvp(args[0], (char*const*)args);
+            fprintf(stderr, "execvp failed: %s\n", strerror(errno));
+            return 1;
+        } else {
+            // parent
+            close(pfd[1]);
+
+            size_t size = 0;
+            while (size < maxAllowedSize) {
+                ssize_t amt = read(pfd[0], buffer + size, maxAllowedSize - size);
+                if (amt == 0) {
+                    break;
+                } else if (amt == -1) {
+                    fprintf(stderr, "read error: %s\n", strerror(errno));
+                    return 1;
+                }
+                size += amt;
+            }
+
+            int status;
+            do {
+                waitpid(pid, &status, 0);
+            } while (!WIFEXITED(status));
+            if (WEXITSTATUS(status) != 0) {
+                return WEXITSTATUS(status);
+            }
+
+            if (size > 0) {
+                uint8_t header[20];
+                uint8_t* p = write_raw_varint(header, (id << 3) | 2);
+                p = write_raw_varint(p, size);
+                int err = write_all(STDOUT_FILENO, header, p-header);
+                if (err != 0) {
+                    fprintf(stderr, "write error: %s\n", strerror(err));
+                    return 1;
+                }
+                err = write_all(STDOUT_FILENO, buffer, size);
+                if (err != 0) {
+                    fprintf(stderr, "write error: %s\n", strerror(err));
+                    return 1;
+                }
+            }
+
+            close(pfd[0]);
+        }
+    }
+
+    return 0;
+}
+
+// ================================================================================
+static void
+usage(FILE* out)
+{
+    fprintf(out, "usage: incident_report -i INPUT [-o OUTPUT]\n");
+    fprintf(out, "\n");
+    fprintf(out, "Pretty-prints an incident report protobuf file.\n");
+    fprintf(out, "  -i INPUT    the input file. INPUT may be '-' to use stdin\n");
+    fprintf(out, "  -o OUTPUT   the output file. OUTPUT may be '-' or omitted to use stdout\n");
+    fprintf(out, "\n");
+    fprintf(out, "\n");
+    fprintf(out, "usage: incident_report [-o OUTPUT] [-t|b] [-s SERIAL] [SECTION...]\n");
+    fprintf(out, "\n");
+    fprintf(out, "Take an incident report over adb (which must be in the PATH).\n");
+    fprintf(out, "  -b          output the incident report raw protobuf format\n");
+    fprintf(out, "  -o OUTPUT   the output file. OUTPUT may be '-' or omitted to use stdout\n");
+    fprintf(out, "  -s SERIAL   sent to adb to choose which device, instead of $ANDROID_SERIAL\n");
+    fprintf(out, "  -t          output the incident report in pretty-printed text format\n");
+    fprintf(out, "\n");
+    fprintf(out, "  SECTION     which bugreport sections to print, either the int code of the\n");
+    fprintf(out, "              section in the Incident proto or the field name.  If ommited,\n");
+    fprintf(out, "              the report will contain all fields\n");
+    fprintf(out, "\n");
+}
+
+int
+main(int argc, char** argv)
+{
+    enum { OUTPUT_TEXT, OUTPUT_PROTO } outputFormat = OUTPUT_TEXT;
+    const char* inFilename = NULL;
+    const char* outFilename = NULL;
+    const char* adbSerial = NULL;
+    bool adbIncidentWorkaround = true;
+    pid_t childPid = -1;
+    vector<string> sections;
+
+    int opt;
+    while ((opt = getopt(argc, argv, "bhi:o:s:tw")) != -1) {
+        switch (opt) {
+            case 'b':
+                outputFormat = OUTPUT_PROTO;
+                break;
+            case 'i':
+                inFilename = optarg;
+                break;
+            case 'o':
+                outFilename = optarg;
+                break;
+            case 's':
+                adbSerial = optarg;
+                break;
+            case 't':
+                outputFormat = OUTPUT_TEXT;
+                break;
+            case 'h':
+                usage(stdout);
+                return 0;
+            case 'w':
+                adbIncidentWorkaround = false;
+                break;
+            default:
+                usage(stderr);
+                return 1;
+        }
+    }
+
+    while (optind < argc) {
+        sections.push_back(argv[optind++]);
+    }
+
+    int inFd;
+    if (inFilename != NULL) {
+        // translate-only mode - oepn the file or use stdin.
+        if (strcmp("-", inFilename) == 0) {
+            inFd = STDIN_FILENO;
+        } else {
+            inFd = open(inFilename, O_RDONLY | O_CLOEXEC);
+            if (inFd < 0) {
+                fprintf(stderr, "unable to open file for read (%s): %s\n", strerror(errno),
+                        inFilename);
+                return 1;
+            }
+        }
+    } else {
+        // pipe mode - run adb shell incident ...
+        int pfd[2];
+        if (pipe(pfd) != 0) {
+            fprintf(stderr, "pipe failed: %s\n", strerror(errno));
+            return 1;
+        }
+
+        childPid = fork();
+        if (childPid == -1) {
+            fprintf(stderr, "fork failed: %s\n", strerror(errno));
+            return 1;
+        } else if (childPid == 0) {
+            dup2(pfd[1], STDOUT_FILENO);
+            close(pfd[0]);
+            close(pfd[1]);
+            // child
+            if (adbIncidentWorkaround) {
+                // TODO: Until the device side incident command is checked in,
+                // the incident_report builds the outer Incident proto by hand
+                // from individual adb shell dumpsys <service> --proto calls,
+                // with a maximum allowed output size.
+                return adb_incident_workaround(adbSerial, sections);
+            }
+
+            // TODO: This is what the real implementation will be...
+            char const** args = (char const**)malloc(sizeof(char*) * (6 + sections.size()));
+            int argpos = 0;
+            args[argpos++] = "adb";
+            if (adbSerial != NULL) {
+                args[argpos++] = "-s";
+                args[argpos++] = adbSerial;
+            }
+            args[argpos++] = "shell";
+            args[argpos++] = "incident";
+            for (vector<string>::const_iterator it=sections.begin(); it!=sections.end(); it++) {
+                args[argpos++] = it->c_str();
+            }
+            args[argpos++] = NULL;
+            execvp(args[0], (char*const*)args);
+            fprintf(stderr, "execvp failed: %s\n", strerror(errno));
+            return 0;
+        } else {
+            // parent
+            inFd = pfd[0];
+            close(pfd[1]);
+        }
+    }
+
+    int outFd;
+    if (outFilename == NULL || strcmp("-", outFilename) == 0) {
+        outFd = STDOUT_FILENO;
+    } else {
+        outFd = open(outFilename, O_CREAT | O_RDWR, 0666);
+        if (outFd < 0) {
+            fprintf(stderr, "unable to open file for write: %s\n", outFilename);
+            return 1;
+        }
+    }
+
+    GenericMessage message;
+
+    Descriptor const* descriptor = IncidentProto::descriptor();
+    FileInputStream infile(inFd);
+    CodedInputStream in(&infile);
+
+    if (!read_message(&in, descriptor, &message)) {
+        fprintf(stderr, "unable to read incident\n");
+        return 1;
+    }
+
+    Out out(outFd);
+
+    print_message(&out, descriptor, &message);
+    out.printf("\n");
+
+    if (childPid != -1) {
+        int status;
+        do {
+            waitpid(childPid, &status, 0);
+        } while (!WIFEXITED(status));
+        if (WEXITSTATUS(status) != 0) {
+            return WEXITSTATUS(status);
+        }
+    }
+
+    return 0;
+}
diff --git a/tools/incident_report/printer.cpp b/tools/incident_report/printer.cpp
new file mode 100644
index 0000000..8111b27
--- /dev/null
+++ b/tools/incident_report/printer.cpp
@@ -0,0 +1,128 @@
+/*
+ * 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 "printer.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#define INITIAL_BUF_SIZE (16*1024)
+
+char const* SPACES = "                                                            ";
+const int SPACE_COUNT = strlen(SPACES);
+
+Out::Out(int fd)
+    :mOut(fd == STDOUT_FILENO ? stdout : fdopen(fd, "w")),
+     mBufSize(INITIAL_BUF_SIZE),
+     mBuf((char*)malloc(INITIAL_BUF_SIZE)),
+     mIndent(0),
+     mPendingIndent(false)
+{
+}
+
+Out::~Out()
+{
+    fclose(mOut);
+}
+
+int
+Out::reallocate(int size)
+{
+    if (size > mBufSize) {
+        char* p = (char*)malloc(size);
+        if (p != NULL) {
+            free(mBuf);
+            mBufSize = size;
+            mBuf = p;
+            return size;
+        }
+    }
+    return mBufSize;
+}
+
+void
+Out::printf(const char* format, ...)
+{
+    if (mPendingIndent) {
+        print_indent();
+        mPendingIndent = false;
+    }
+
+    int len;
+
+    va_list args;
+    va_start(args, format);
+
+    len = vsnprintf(mBuf, mBufSize, format, args);
+    bool truncated = (len >= mBufSize) && (reallocate(len) < len);
+    
+    len = vsnprintf(mBuf, mBufSize, format, args);
+    va_end(args);
+
+    if (len > 0) {
+        if (mIndent == 0) {
+            fwrite(mBuf, len, 1, mOut);
+        } else {
+            char* last = mBuf;
+            char* p;
+            do {
+                p = strchr(last, '\n');
+                int size = p != NULL ? p - last + 1 : strlen(last);
+                fwrite(last, size, 1, mOut);
+                if (p != NULL) {
+                    if (p[1] == '\0') {
+                        mPendingIndent = true;
+                    } else {
+                        print_indent();
+                    }
+                }
+                last = p+1;
+            } while (p != NULL);
+        }
+    }
+}
+
+void
+Out::indent()
+{
+    mPendingIndent = true;
+    mIndent += 2;
+}
+
+void
+Out::dedent()
+{
+    if (mIndent > 0) {
+        mIndent -= 2;
+    }
+}
+
+void
+Out::print_indent()
+{
+#if 0
+    fprintf(mOut, "[%d]", mIndent);
+#else
+    int indent = mIndent;
+    while (indent > SPACE_COUNT) {
+        fwrite(SPACES, SPACE_COUNT, 1, mOut);
+        indent -= SPACE_COUNT;
+    }
+    fwrite(SPACES + SPACE_COUNT - indent, indent, 1, mOut);
+#endif
+}
diff --git a/tools/incident_report/printer.h b/tools/incident_report/printer.h
new file mode 100644
index 0000000..ed93fa1
--- /dev/null
+++ b/tools/incident_report/printer.h
@@ -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.
+ */
+
+#ifndef PRINTER_H
+#define PRINTER_H
+
+#include <stdio.h>
+
+class Out
+{
+public:
+    Out(int fd);
+    ~Out();
+
+    void printf(const char* format, ...);
+
+    void indent();
+    void dedent();
+
+private:
+    FILE* mOut;
+    int mBufSize;
+    char* mBuf;
+    int mIndent;
+    bool mPendingIndent;
+
+    int reallocate(int size);
+    void print_indent();
+};
+
+#endif // PRINTER_H
diff --git a/tools/incident_section_gen/Android.mk b/tools/incident_section_gen/Android.mk
new file mode 100644
index 0000000..acf3f83
--- /dev/null
+++ b/tools/incident_section_gen/Android.mk
@@ -0,0 +1,35 @@
+#
+# 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.
+#
+LOCAL_PATH:= $(call my-dir)
+
+# ==========================================================
+# Build the host executable: protoc-gen-javastream
+# ==========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := incident-section-gen
+LOCAL_CFLAGS += -g -O0
+LOCAL_C_INCLUDES := \
+    external/protobuf/src
+LOCAL_SRC_FILES := \
+    main.cpp
+LOCAL_LDFLAGS := -ldl
+LOCAL_SHARED_LIBRARIES := \
+    libplatformprotos \
+    libprotobuf-cpp-full
+
+include $(BUILD_HOST_EXECUTABLE)
+
diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp
new file mode 100644
index 0000000..d004810
--- /dev/null
+++ b/tools/incident_section_gen/main.cpp
@@ -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.
+ */
+
+
+#include <frameworks/base/core/proto/android/os/incident_proto.pb.h>
+
+
+#include <map>
+
+using namespace android::os;
+using namespace google::protobuf;
+using namespace google::protobuf::io;
+using namespace google::protobuf::internal;
+using namespace std;
+
+int
+main(int, const char**)
+{
+    map<string,FieldDescriptor const*> sections;
+    int N;
+
+    printf("// Auto generated file. Do not modify\n");
+    printf("\n");
+    printf("#include \"incident_sections.h\"\n");
+    printf("\n");
+
+    Descriptor const* descriptor = IncidentProto::descriptor();
+    N = descriptor->field_count();
+    for (int i=0; i<N; i++) {
+        const FieldDescriptor* field = descriptor->field(i);
+        if (field->type() == FieldDescriptor::TYPE_MESSAGE) {
+            sections[field->name()] = field;
+        }
+    }
+
+    printf("IncidentSection const INCIDENT_SECTIONS[] = {\n");
+    N = sections.size();
+    int i = 0;
+    for (map<string,FieldDescriptor const*>::const_iterator it = sections.begin();
+            it != sections.end(); it++, i++) {
+        const FieldDescriptor* field = it->second;
+        printf("    { %d, \"%s\" }", field->number(), field->name().c_str());
+        if (i != N-1) {
+            printf(",\n");
+        } else {
+            printf("\n");
+        }
+    }
+    printf("};\n");
+
+    printf("const int INCIDENT_SECTION_COUNT = %d;\n", N);
+
+    return 0;
+}
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index a0ded87..4b9815d 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -34,7 +34,6 @@
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.util.DisplayMetrics;
-import android.view.AppTransitionAnimationSpec;
 
 import java.lang.Override;
 
@@ -78,11 +77,10 @@
     // ---- unused implementation of IWindowManager ----
 
     @Override
-    public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
-            boolean arg5, boolean arg6, int arg7, int arg8, boolean arg9, boolean arg10,
-            Rect arg11, Configuration arg12, int arg13, boolean arg14, boolean arg15, int arg16,
-            int arg17, boolean arg18)
-            throws RemoteException {
+    public void addAppToken(int addPos, IApplicationToken token, int taskId,
+            int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int configChanges,
+            boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
+            int targetSdkVersion, int rotationAnimationHint) throws RemoteException {
         // TODO Auto-generated method stub
     }
 
@@ -327,9 +325,7 @@
     }
 
     @Override
-    public void setAppTask(IBinder arg0, int arg1, int arg2, Rect arg3, Configuration arg4,
-            int arg5, boolean arg6, boolean arg7)
-            throws RemoteException {
+    public void addAppToTask(IBinder arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
     }
 
diff --git a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
new file mode 100755
index 0000000..c328748
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
@@ -0,0 +1,196 @@
+/*
+ * 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 android.net.wifi;
+
+import android.Manifest.permission;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.net.INetworkScoreCache;
+import android.net.NetworkKey;
+import android.net.ScoredNetwork;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * {@link INetworkScoreCache} implementation for Wifi Networks.
+ *
+ * @hide
+ */
+public class WifiNetworkScoreCache extends INetworkScoreCache.Stub {
+    private static final String TAG = "WifiNetworkScoreCache";
+    private static final boolean DBG = false;
+
+    // A Network scorer returns a score in the range [-128, +127]
+    // We treat the lowest possible score as though there were no score, effectively allowing the
+    // scorer to provide an RSSI threshold below which a network should not be used.
+    public static final int INVALID_NETWORK_SCORE = Byte.MIN_VALUE;
+    private final Context mContext;
+
+    // The key is of the form "<ssid>"<bssid>
+    // TODO: What about SSIDs that can't be encoded as UTF-8?
+    private final Map<String, ScoredNetwork> mNetworkCache;
+
+    public WifiNetworkScoreCache(Context context) {
+        mContext = context;
+        mNetworkCache = new HashMap<String, ScoredNetwork>();
+    }
+
+    @Override public final void updateScores(List<ScoredNetwork> networks) {
+      if (networks == null) {
+           return;
+       }
+       Log.e(TAG, "updateScores list size=" + networks.size());
+
+       synchronized(mNetworkCache) {
+           for (ScoredNetwork network : networks) {
+               String networkKey = buildNetworkKey(network);
+               if (networkKey == null) continue;
+               mNetworkCache.put(networkKey, network);
+           }
+       }
+    }
+
+    @Override public final void clearScores() {
+        synchronized (mNetworkCache) {
+            mNetworkCache.clear();
+        }
+    }
+
+    /**
+     * Returns whether there is any score info for the given ScanResult.
+     *
+     * This includes null-score info, so it should only be used when determining whether to request
+     * scores from the network scorer.
+     */
+    public boolean isScoredNetwork(ScanResult result) {
+        return getScoredNetwork(result) != null;
+    }
+
+    /**
+     * Returns whether there is a non-null score curve for the given ScanResult.
+     *
+     * A null score curve has special meaning - we should never connect to an ephemeral network if
+     * the score curve is null.
+     */
+    public boolean hasScoreCurve(ScanResult result) {
+        ScoredNetwork network = getScoredNetwork(result);
+        return network != null && network.rssiCurve != null;
+    }
+
+    public int getNetworkScore(ScanResult result) {
+
+        int score = INVALID_NETWORK_SCORE;
+
+        ScoredNetwork network = getScoredNetwork(result);
+        if (network != null && network.rssiCurve != null) {
+            score = network.rssiCurve.lookupScore(result.level);
+            if (DBG) {
+                Log.e(TAG, "getNetworkScore found scored network " + network.networkKey
+                        + " score " + Integer.toString(score)
+                        + " RSSI " + result.level);
+            }
+        }
+        return score;
+    }
+
+    /**
+     * Returns the ScoredNetwork metered hint for a given ScanResult.
+     *
+     * If there is no ScoredNetwork associated with the ScanResult then false will be returned.
+     */
+    public boolean getMeteredHint(ScanResult result) {
+        ScoredNetwork network = getScoredNetwork(result);
+        return network != null && network.meteredHint;
+    }
+
+    public int getNetworkScore(ScanResult result, boolean isActiveNetwork) {
+
+        int score = INVALID_NETWORK_SCORE;
+
+        ScoredNetwork network = getScoredNetwork(result);
+        if (network != null && network.rssiCurve != null) {
+            score = network.rssiCurve.lookupScore(result.level, isActiveNetwork);
+            if (DBG) {
+                Log.e(TAG, "getNetworkScore found scored network " + network.networkKey
+                        + " score " + Integer.toString(score)
+                        + " RSSI " + result.level
+                        + " isActiveNetwork " + isActiveNetwork);
+            }
+        }
+        return score;
+    }
+
+    private ScoredNetwork getScoredNetwork(ScanResult result) {
+        String key = buildNetworkKey(result);
+        if (key == null) return null;
+
+        //find it
+        synchronized(mNetworkCache) {
+            ScoredNetwork network = mNetworkCache.get(key);
+            return network;
+        }
+    }
+
+     private String buildNetworkKey(ScoredNetwork network) {
+        if (network == null || network.networkKey == null) return null;
+        if (network.networkKey.wifiKey == null) return null;
+        if (network.networkKey.type == NetworkKey.TYPE_WIFI) {
+            String key = network.networkKey.wifiKey.ssid;
+            if (key == null) return null;
+            if (network.networkKey.wifiKey.bssid != null) {
+                key = key + network.networkKey.wifiKey.bssid;
+            }
+            return key;
+        }
+        return null;
+    }
+
+    private String buildNetworkKey(ScanResult result) {
+        if (result == null || result.SSID == null) {
+            return null;
+        }
+        StringBuilder key = new StringBuilder("\"");
+        key.append(result.SSID);
+        key.append("\"");
+        if (result.BSSID != null) {
+            key.append(result.BSSID);
+        }
+        return key.toString();
+    }
+
+    @Override protected final void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+        mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG);
+        writer.println("WifiNetworkScoreCache");
+        writer.println("  All score curves:");
+        for (Map.Entry<String, ScoredNetwork> entry : mNetworkCache.entrySet()) {
+            ScoredNetwork scoredNetwork = entry.getValue();
+            writer.println("    " + entry.getKey() + ": " + scoredNetwork.rssiCurve
+                    + ", meteredHint=" + scoredNetwork.meteredHint);
+        }
+        writer.println("  Current network scores:");
+        WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+        for (ScanResult scanResult : wifiManager.getScanResults()) {
+            writer.println("    " + buildNetworkKey(scanResult) + ": " + getNetworkScore(scanResult));
+        }
+    }
+
+}
diff --git a/wifi/tests/Android.mk b/wifi/tests/Android.mk
index 5850fee..eac49d2 100644
--- a/wifi/tests/Android.mk
+++ b/wifi/tests/Android.mk
@@ -50,6 +50,7 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
 	android-support-test \
+	guava \
 	mockito-target-minus-junit4 \
 	frameworks-base-testutils \
 
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java
new file mode 100644
index 0000000..f8549b9
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java
@@ -0,0 +1,156 @@
+/*
+ * 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.*;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.NetworkKey;
+import android.net.RssiCurve;
+import android.net.ScoredNetwork;
+import android.net.WifiKey;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Rule;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Unit tests for {@link WifiNetworkScoreCache}. */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class WifiNetworkScoreCacheTest {
+
+  @Mock public Context mockContext; // isn't used, can be null
+  @Mock private RssiCurve mockRssiCurve;
+
+  public static final String SSID = "ssid";
+  public static final String FORMATTED_SSID = "\"" + SSID + "\"";
+  public static final String BSSID = "AA:AA:AA:AA:AA:AA";
+
+  public static final WifiKey VALID_KEY = new WifiKey(FORMATTED_SSID, BSSID);
+
+  public static final ScanResult VALID_SCAN_RESULT = buildScanResult(SSID, BSSID);
+
+  private ScoredNetwork mValidScoredNetwork;
+  private WifiNetworkScoreCache mScoreCache =
+      new WifiNetworkScoreCache(mockContext);
+
+  private static ScanResult buildScanResult(String ssid, String bssid) {
+    return new ScanResult(
+         WifiSsid.createFromAsciiEncoded(ssid),
+         bssid,
+         "" /* caps */,
+         0 /* level */,
+         0 /* frequency */,
+         0 /* tsf */,
+         0 /* distCm */,
+         0 /* distSdCm*/);
+  }
+
+  private static ScoredNetwork buildScoredNetwork(WifiKey key, RssiCurve curve) {
+    return new ScoredNetwork(new NetworkKey(key), curve);
+  }
+
+  // Called from setup
+  private void initializeCacheWithValidScoredNetwork() {
+    mScoreCache.updateScores(ImmutableList.of(mValidScoredNetwork));
+  }
+
+  @Before
+  public void setUp() {
+    MockitoAnnotations.initMocks(this);
+    mValidScoredNetwork = buildScoredNetwork(VALID_KEY, mockRssiCurve);
+    mScoreCache = new WifiNetworkScoreCache(mockContext);
+    initializeCacheWithValidScoredNetwork();
+  }
+
+
+  @Test
+  public void isScoredNetworkShouldReturnTrueAfterUpdateScoresIsCalled() {
+    assertTrue(mScoreCache.isScoredNetwork(VALID_SCAN_RESULT));
+  }
+
+  @Test
+  public void isScoredNetworkShouldReturnFalseAfterClearScoresIsCalled() {
+    mScoreCache.clearScores();
+    assertFalse(mScoreCache.isScoredNetwork(VALID_SCAN_RESULT));
+  }
+
+  @Test
+  public void updateScoresShouldAddNewNetwork() {
+    WifiKey key2 = new WifiKey("\"ssid2\"", BSSID);
+    ScoredNetwork network2 = buildScoredNetwork(key2, mockRssiCurve);
+    ScanResult result2 = buildScanResult("ssid2", BSSID);
+
+    mScoreCache.updateScores(ImmutableList.of(network2));
+
+    assertTrue(mScoreCache.isScoredNetwork(VALID_SCAN_RESULT));
+    assertTrue(mScoreCache.isScoredNetwork(result2));
+  }
+
+  @Test
+  public void hasScoreCurveShouldReturnTrue() {
+    assertTrue(mScoreCache.hasScoreCurve(VALID_SCAN_RESULT));
+  }
+
+  @Test
+  public void hasScoreCurveShouldReturnFalseWhenNoCachedNetwork() {
+    ScanResult unscored = buildScanResult("fake", BSSID);
+    assertFalse(mScoreCache.hasScoreCurve(unscored));
+  }
+
+  @Test
+  public void hasScoreCurveShouldReturnFalseWhenScoredNetworkHasNoCurve() {
+    ScoredNetwork noCurve = buildScoredNetwork(VALID_KEY, null /* rssiCurve */);
+    mScoreCache.updateScores(ImmutableList.of(noCurve));
+
+    assertFalse(mScoreCache.hasScoreCurve(VALID_SCAN_RESULT));
+  }
+
+  @Test
+  public void getNetworkScoreShouldReturnScore() {
+    final byte score = 50;
+    final int rssi = -70;
+    ScanResult result = new ScanResult(VALID_SCAN_RESULT);
+    result.level = rssi;
+
+    when(mockRssiCurve.lookupScore(rssi)).thenReturn(score);
+
+    assertEquals(score, mScoreCache.getNetworkScore(result));
+  }
+
+  @Test
+  public void getMeteredHintShouldReturnFalse() {
+    assertFalse(mScoreCache.getMeteredHint(VALID_SCAN_RESULT));
+  }
+
+  @Test
+  public void getMeteredHintShouldReturnTrue() {
+    ScoredNetwork network =
+        new ScoredNetwork(new NetworkKey(VALID_KEY), mockRssiCurve, true /* metered Hint */);
+    mScoreCache.updateScores(ImmutableList.of(network));
+
+    assertTrue(mScoreCache.getMeteredHint(VALID_SCAN_RESULT));
+  }
+}