Merge "Fix monkey NPE"
diff --git a/Android.bp b/Android.bp
index 010b2b4..dba49ce 100644
--- a/Android.bp
+++ b/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 subdirs = [
+    "libs/*",
     "native/android",
     "native/graphics/jni",
 ]
diff --git a/Android.mk b/Android.mk
index 7103f67..405f957 100644
--- a/Android.mk
+++ b/Android.mk
@@ -45,6 +45,7 @@
        core/java/android/app/admin/SecurityLogTags.logtags \
        core/java/android/content/EventLogTags.logtags \
        core/java/android/speech/tts/EventLogTags.logtags \
+       core/java/android/net/EventLogTags.logtags \
        core/java/android/webkit/EventLogTags.logtags \
        core/java/com/android/internal/logging/EventLogTags.logtags \
 
@@ -79,6 +80,7 @@
 	core/java/android/app/IBackupAgent.aidl \
 	core/java/android/app/IEphemeralResolver.aidl \
 	core/java/android/app/IInstrumentationWatcher.aidl \
+	core/java/android/app/IOnNotificationChannelCreatedListener.aidl \
 	core/java/android/app/INotificationManager.aidl \
 	core/java/android/app/IProcessObserver.aidl \
 	core/java/android/app/ISearchManager.aidl \
@@ -516,7 +518,7 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(framework_res_R_stamp)
 
 LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart conscrypt okhttp core-junit bouncycastle ext
+LOCAL_JAVA_LIBRARIES := core-oj core-libart conscrypt okhttp legacy-test bouncycastle ext
 
 LOCAL_STATIC_JAVA_LIBRARIES :=                          \
     framework-protos                                    \
diff --git "a/\135" "b/\135"
new file mode 100644
index 0000000..5619151
--- /dev/null
+++ "b/\135"
@@ -0,0 +1,12 @@
+NetworkNotificationManager: logging improvements
+
+TODO: squash me
+# Please enter the commit message for your changes. Lines starting
+# with '#' will be ignored, and an empty message aborts the commit.
+# On branch notification_tagging
+# Your branch is ahead of 'goog/master' by 2 commits.
+#   (use "git push" to publish your local commits)
+#
+# Changes to be committed:
+#	modified:   services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+#
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_10.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_10.xml
new file mode 100644
index 0000000..791f587
--- /dev/null
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_10.xml
@@ -0,0 +1,43 @@
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<!-- Contains 10 sizes to choose from when auto-sizing -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="400dp"
+          android:layout_height="600dp"
+          android:text="@string/long_text"
+          android:textDirection="rtl"
+          android:autoSizeText="xy"
+          android:autoSizeMinTextSize="10px"
+          android:textSize="20px"
+          android:autoSizeStepGranularity="1px"/>
+
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_100.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_100.xml
new file mode 100644
index 0000000..cca4a52
--- /dev/null
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_100.xml
@@ -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
+  -->
+
+<!-- Contains 100 sizes to choose from when auto-sizing -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="400dp"
+          android:layout_height="600dp"
+          android:text="@string/long_text"
+          android:textDirection="rtl"
+          android:autoSizeText="xy"
+          android:autoSizeMinTextSize="10px"
+          android:textSize="110px"
+          android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_1000.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_1000.xml
new file mode 100644
index 0000000..bb9fc5e
--- /dev/null
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_1000.xml
@@ -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
+  -->
+
+<!-- Contains 1000 sizes to choose from when auto-sizing -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="400dp"
+          android:layout_height="600dp"
+          android:text="@string/long_text"
+          android:textDirection="rtl"
+          android:autoSizeText="xy"
+          android:autoSizeMinTextSize="10px"
+          android:textSize="1010px"
+          android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_10000.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_10000.xml
new file mode 100644
index 0000000..e0e5878
--- /dev/null
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_10000.xml
@@ -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
+  -->
+
+<!-- Contains 10000 sizes to choose from when auto-sizing -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="400dp"
+          android:layout_height="600dp"
+          android:text="@string/long_text"
+          android:textDirection="rtl"
+          android:autoSizeText="xy"
+          android:autoSizeMinTextSize="10px"
+          android:textSize="10010px"
+          android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_100000.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_100000.xml
new file mode 100644
index 0000000..4f66805
--- /dev/null
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_100000.xml
@@ -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
+  -->
+
+<!-- Contains 100000 sizes!!! to choose from when auto-sizing -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="400dp"
+          android:layout_height="600dp"
+          android:text="@string/long_text"
+          android:textDirection="rtl"
+          android:autoSizeText="xy"
+          android:autoSizeMinTextSize="10px"
+          android:textSize="100010px"
+          android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_300.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_300.xml
new file mode 100644
index 0000000..d3a4040
--- /dev/null
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_300.xml
@@ -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
+  -->
+
+<!-- Contains 300 sizes to choose from when auto-sizing -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="400dp"
+          android:layout_height="600dp"
+          android:text="@string/long_text"
+          android:textDirection="rtl"
+          android:autoSizeText="xy"
+          android:autoSizeMinTextSize="10px"
+          android:textSize="310px"
+          android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_5.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_5.xml
new file mode 100644
index 0000000..c7982e7
--- /dev/null
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_5.xml
@@ -0,0 +1,42 @@
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<!-- Contains 5 sizes to choose from when auto-sizing -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="400dp"
+          android:layout_height="600dp"
+          android:text="@string/long_text"
+          android:textDirection="rtl"
+          android:autoSizeText="xy"
+          android:autoSizeMinTextSize="10px"
+          android:textSize="15px"
+          android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_50.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_50.xml
new file mode 100644
index 0000000..b009889
--- /dev/null
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_50.xml
@@ -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
+  -->
+
+<!-- Contains 50 sizes to choose from when auto-sizing -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="400dp"
+          android:layout_height="600dp"
+          android:text="@string/long_text"
+          android:textDirection="rtl"
+          android:autoSizeText="xy"
+          android:autoSizeMinTextSize="10px"
+          android:textSize="60px"
+          android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_500.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_500.xml
new file mode 100644
index 0000000..f59d751
--- /dev/null
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_500.xml
@@ -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
+  -->
+
+<!-- Contains 500 sizes to choose from when auto-sizing -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="400dp"
+          android:layout_height="600dp"
+          android:text="@string/long_text"
+          android:textDirection="rtl"
+          android:autoSizeText="xy"
+          android:autoSizeMinTextSize="10px"
+          android:textSize="510px"
+          android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_basic_textview_layout.xml b/apct-tests/perftests/core/res/layout/test_basic_textview_layout.xml
new file mode 100644
index 0000000..bc60ad4
--- /dev/null
+++ b/apct-tests/perftests/core/res/layout/test_basic_textview_layout.xml
@@ -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
+  -->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="300dp"
+          android:layout_height="300dp"
+          android:text="@string/long_text" />
diff --git a/apct-tests/perftests/core/res/values/strings.xml b/apct-tests/perftests/core/res/values/strings.xml
new file mode 100644
index 0000000..5d1f6f0
--- /dev/null
+++ b/apct-tests/perftests/core/res/values/strings.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_text">text text text text text text text text text text text text
+        text text text text text text text text text text text text text text text text
+        text text text text text text text text text text text text text text text text
+        text text text text text text text text text text text text text text text text
+        text text text text text text text text text text text text text text text text
+        text text text text text text text text text text text text text text text text
+        text text text text text text text typo text text text text text text text text
+        text text text text text text text text text text text text text text text text
+        text text text text text text text text text text text text text text text text
+        text text text text text text text text text text text text text text text text
+        text text text text text text text text text text text text text text text text
+        text text text text text text text text text text text text </string>
+</resources>
diff --git a/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java
new file mode 100644
index 0000000..6ee6f70
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.widget;
+
+import android.app.Activity;
+import android.os.Looper;
+import android.os.Bundle;
+import android.perftests.utils.PerfStatusReporter;
+import android.util.Log;
+import android.view.View;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.StubActivity;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.InstrumentationRegistry;
+
+import com.android.perftests.core.R;
+
+import java.util.Locale;
+import java.util.Collection;
+import java.util.Arrays;
+
+import org.junit.Test;
+import org.junit.Rule;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertTrue;
+
+@LargeTest
+@RunWith(Parameterized.class)
+public class TextViewAutoSizeLayoutPerfTest {
+    @Parameters(name = "{0}")
+    public static Collection layouts() {
+        return Arrays.asList(new Object[][] {
+                { "Basic TextView - no autosize", R.layout.test_basic_textview_layout},
+                { "Autosize TextView 5 sizes", R.layout.test_autosize_textview_5},
+                { "Autosize TextView 10 sizes", R.layout.test_autosize_textview_10},
+                { "Autosize TextView 50 sizes", R.layout.test_autosize_textview_50},
+                { "Autosize TextView 100 sizes", R.layout.test_autosize_textview_100},
+                { "Autosize TextView 300 sizes", R.layout.test_autosize_textview_300},
+                { "Autosize TextView 500 sizes", R.layout.test_autosize_textview_500},
+                { "Autosize TextView 1000 sizes", R.layout.test_autosize_textview_1000},
+                { "Autosize TextView 10000 sizes", R.layout.test_autosize_textview_10000},
+                { "Autosize TextView 100000 sizes", R.layout.test_autosize_textview_100000}
+        });
+    }
+
+    private int mLayoutId;
+
+    public TextViewAutoSizeLayoutPerfTest(String key, int layoutId) {
+        mLayoutId = layoutId;
+    }
+
+    @Rule
+    public ActivityTestRule<StubActivity> mActivityRule =
+            new ActivityTestRule(StubActivity.class);
+
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Test
+    public void testConstruction() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            assertTrue("We should be running on the main thread",
+                    Looper.getMainLooper().getThread() == Thread.currentThread());
+            assertTrue("We should be running on the main thread",
+                    Looper.myLooper() == Looper.getMainLooper());
+            BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+            Activity activity = mActivityRule.getActivity();
+            activity.setContentView(mLayoutId);
+
+            while (state.keepRunning()) {
+                TextView textView = new TextView(activity);
+                // TextView#onMeasure() gets called, which triggers TextView#autoSizeText()
+                // which is the method we want to benchmark.
+                textView.requestLayout();
+            }
+        });
+    }
+}
diff --git a/api/current.txt b/api/current.txt
index 6b140b3..5020a425 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -99,6 +99,7 @@
     field public static final java.lang.String READ_FRAME_BUFFER = "android.permission.READ_FRAME_BUFFER";
     field public static final deprecated java.lang.String READ_INPUT_STATE = "android.permission.READ_INPUT_STATE";
     field public static final java.lang.String READ_LOGS = "android.permission.READ_LOGS";
+    field public static final java.lang.String READ_PHONE_NUMBER = "android.permission.READ_PHONE_NUMBER";
     field public static final java.lang.String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE";
     field public static final java.lang.String READ_SMS = "android.permission.READ_SMS";
     field public static final java.lang.String READ_SYNC_SETTINGS = "android.permission.READ_SYNC_SETTINGS";
@@ -793,10 +794,12 @@
     field public static final int layout_margin = 16842998; // 0x10100f6
     field public static final int layout_marginBottom = 16843002; // 0x10100fa
     field public static final int layout_marginEnd = 16843702; // 0x10103b6
+    field public static final int layout_marginHorizontal = 16844091; // 0x101053b
     field public static final int layout_marginLeft = 16842999; // 0x10100f7
     field public static final int layout_marginRight = 16843001; // 0x10100f9
     field public static final int layout_marginStart = 16843701; // 0x10103b5
     field public static final int layout_marginTop = 16843000; // 0x10100f8
+    field public static final int layout_marginVertical = 16844092; // 0x101053c
     field public static final int layout_row = 16843643; // 0x101037b
     field public static final int layout_rowSpan = 16843644; // 0x101037c
     field public static final int layout_rowWeight = 16843864; // 0x1010458
@@ -864,7 +867,7 @@
     field public static final int mediaRouteTypes = 16843694; // 0x10103ae
     field public static final int menuCategory = 16843230; // 0x10101de
     field public static final int mimeType = 16842790; // 0x1010026
-    field public static final int min = 16843367; // 0x1010267
+    field public static final int min = 16844089; // 0x1010539
     field public static final int minDate = 16843583; // 0x101033f
     field public static final int minEms = 16843098; // 0x101015a
     field public static final int minHeight = 16843072; // 0x1010140
@@ -927,11 +930,13 @@
     field public static final int padding = 16842965; // 0x10100d5
     field public static final int paddingBottom = 16842969; // 0x10100d9
     field public static final int paddingEnd = 16843700; // 0x10103b4
+    field public static final int paddingHorizontal = 16844093; // 0x101053d
     field public static final int paddingLeft = 16842966; // 0x10100d6
     field public static final int paddingMode = 16843863; // 0x1010457
     field public static final int paddingRight = 16842968; // 0x10100d8
     field public static final int paddingStart = 16843699; // 0x10103b3
     field public static final int paddingTop = 16842967; // 0x10100d7
+    field public static final int paddingVertical = 16844094; // 0x101053e
     field public static final int panelBackground = 16842846; // 0x101005e
     field public static final int panelColorBackground = 16842849; // 0x1010061
     field public static final int panelColorForeground = 16842848; // 0x1010060
@@ -1050,7 +1055,7 @@
     field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093
     field public static final int ringtoneType = 16843257; // 0x10101f9
     field public static final int rotation = 16843558; // 0x1010326
-    field public static final int rotationAnimation = 16843688; // 0x10103a8
+    field public static final int rotationAnimation = 16844090; // 0x101053a
     field public static final int rotationX = 16843559; // 0x1010327
     field public static final int rotationY = 16843560; // 0x1010328
     field public static final int roundIcon = 16844076; // 0x101052c
@@ -2799,9 +2804,14 @@
 
   public static class GestureDescription.StrokeDescription {
     ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long);
+    ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long, int, boolean);
+    method public int getContinuedStrokeId();
     method public long getDuration();
+    method public int getId();
     method public android.graphics.Path getPath();
     method public long getStartTime();
+    method public boolean isContinued();
+    field public static final int INVALID_STROKE_ID = -1; // 0xffffffff
   }
 
 }
@@ -4067,6 +4077,7 @@
     field public static final java.lang.String OPSTR_READ_CELL_BROADCASTS = "android:read_cell_broadcasts";
     field public static final java.lang.String OPSTR_READ_CONTACTS = "android:read_contacts";
     field public static final java.lang.String OPSTR_READ_EXTERNAL_STORAGE = "android:read_external_storage";
+    field public static final java.lang.String OPSTR_READ_PHONE_NUMBER = "android:read_phone_number";
     field public static final java.lang.String OPSTR_READ_PHONE_STATE = "android:read_phone_state";
     field public static final java.lang.String OPSTR_READ_SMS = "android:read_sms";
     field public static final java.lang.String OPSTR_RECEIVE_MMS = "android:receive_mms";
@@ -5363,17 +5374,19 @@
     ctor protected NotificationChannel(android.os.Parcel);
     method public boolean canBypassDnd();
     method public int describeContents();
+    method public void enableVibration(boolean);
     method public java.lang.String getId();
     method public int getImportance();
     method public int getLockscreenVisibility();
     method public java.lang.CharSequence getName();
     method public android.net.Uri getSound();
+    method public long[] getVibrationPattern();
     method public void setBypassDnd(boolean);
     method public void setImportance(int);
     method public void setLights(boolean);
     method public void setLockscreenVisibility(int);
     method public void setSound(android.net.Uri);
-    method public void setVibration(boolean);
+    method public void setVibrationPattern(long[]);
     method public boolean shouldShowLights();
     method public boolean shouldVibrate();
     method public void writeToParcel(android.os.Parcel, int);
@@ -5387,7 +5400,7 @@
     method public void cancel(int);
     method public void cancel(java.lang.String, int);
     method public void cancelAll();
-    method public void createNotificationChannel(android.app.NotificationChannel);
+    method public void createNotificationChannel(android.app.NotificationChannel, android.app.NotificationManager.OnNotificationChannelCreatedListener, android.os.Handler);
     method public void deleteNotificationChannel(java.lang.String);
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
     method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
@@ -5421,6 +5434,10 @@
     field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
   }
 
+  public static abstract interface NotificationManager.OnNotificationChannelCreatedListener {
+    method public abstract void onNotificationChannelCreated(android.app.NotificationChannel);
+  }
+
   public static class NotificationManager.Policy implements android.os.Parcelable {
     ctor public NotificationManager.Policy(int, int, int);
     ctor public NotificationManager.Policy(int, int, int, int);
@@ -6173,6 +6190,7 @@
     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_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";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME";
@@ -8804,6 +8822,7 @@
     field public static final java.lang.String CATEGORY_SELECTED_ALTERNATIVE = "android.intent.category.SELECTED_ALTERNATIVE";
     field public static final java.lang.String CATEGORY_TAB = "android.intent.category.TAB";
     field public static final java.lang.String CATEGORY_TEST = "android.intent.category.TEST";
+    field public static final java.lang.String CATEGORY_TYPED_OPENABLE = "android.intent.category.TYPED_OPENABLE";
     field public static final java.lang.String CATEGORY_UNIT_TEST = "android.intent.category.UNIT_TEST";
     field public static final java.lang.String CATEGORY_VOICE = "android.intent.category.VOICE";
     field public static final android.os.Parcelable.Creator<android.content.Intent> CREATOR;
@@ -12002,6 +12021,7 @@
     method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace, android.graphics.ColorSpace, android.graphics.ColorSpace.RenderIntent);
     method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace);
     method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace, android.graphics.ColorSpace.RenderIntent);
+    method public static android.graphics.ColorSpace.Renderer createRenderer();
     method public float[] fromXyz(float, float, float);
     method public abstract float[] fromXyz(float[]);
     method public static android.graphics.ColorSpace get(android.graphics.ColorSpace.Named);
@@ -12083,6 +12103,15 @@
     enum_constant public static final android.graphics.ColorSpace.RenderIntent SATURATION;
   }
 
+  public static class ColorSpace.Renderer {
+    method public android.graphics.ColorSpace.Renderer add(android.graphics.ColorSpace, int);
+    method public android.graphics.ColorSpace.Renderer add(android.graphics.ColorSpace, float, float, float, int);
+    method public android.graphics.ColorSpace.Renderer clip(boolean);
+    method public android.graphics.Bitmap render();
+    method public android.graphics.ColorSpace.Renderer showWhitePoint(boolean);
+    method public android.graphics.ColorSpace.Renderer size(int);
+  }
+
   public static class ColorSpace.Rgb extends android.graphics.ColorSpace {
     ctor public ColorSpace.Rgb(java.lang.String, float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator);
     ctor public ColorSpace.Rgb(java.lang.String, float[], float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator, float, float);
@@ -20177,8 +20206,8 @@
   }
 
   public class AudioTrack implements android.media.AudioRouting {
-    ctor public AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
-    ctor public AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
+    ctor public deprecated AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
+    ctor public deprecated AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
     ctor public AudioTrack(android.media.AudioAttributes, android.media.AudioFormat, int, int, int) throws java.lang.IllegalArgumentException;
     method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
     method public deprecated void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
@@ -21462,11 +21491,12 @@
     method public void prepareAsync() throws java.lang.IllegalStateException;
     method public void release();
     method public void reset();
+    method public void seekTo(int, int) throws java.lang.IllegalStateException;
     method public void seekTo(int) throws java.lang.IllegalStateException;
     method public void selectTrack(int) throws java.lang.IllegalStateException;
     method public void setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
     method public void setAudioSessionId(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public void setAudioStreamType(int);
+    method public deprecated void setAudioStreamType(int);
     method public void setAuxEffectSendLevel(float);
     method public void setDataSource(android.content.Context, android.net.Uri) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
     method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
@@ -21514,6 +21544,10 @@
     field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3
     field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc
     field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
+    field public static final int SEEK_CLOSEST = 3; // 0x3
+    field public static final int SEEK_CLOSEST_SYNC = 2; // 0x2
+    field public static final int SEEK_NEXT_SYNC = 1; // 0x1
+    field public static final int SEEK_PREVIOUS_SYNC = 0; // 0x0
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
   }
@@ -25544,7 +25578,7 @@
     method public static android.opengl.EGLContext eglCreateContext(android.opengl.EGLDisplay, android.opengl.EGLConfig, android.opengl.EGLContext, int[], int);
     method public static android.opengl.EGLSurface eglCreatePbufferFromClientBuffer(android.opengl.EGLDisplay, int, int, android.opengl.EGLConfig, int[], int);
     method public static android.opengl.EGLSurface eglCreatePbufferSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int[], int);
-    method public static android.opengl.EGLSurface eglCreatePixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int, int[], int);
+    method public static deprecated android.opengl.EGLSurface eglCreatePixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int, int[], int);
     method public static android.opengl.EGLSurface eglCreateWindowSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, java.lang.Object, int[], int);
     method public static boolean eglDestroyContext(android.opengl.EGLDisplay, android.opengl.EGLContext);
     method public static boolean eglDestroySurface(android.opengl.EGLDisplay, android.opengl.EGLSurface);
@@ -29654,6 +29688,7 @@
     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";
+    field public static final java.lang.String DISALLOW_BLUETOOTH = "no_bluetooth";
     field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
     field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
     field public static final java.lang.String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
@@ -30009,6 +30044,7 @@
     method protected long getPersistedLong(long);
     method protected java.lang.String getPersistedString(java.lang.String);
     method public java.util.Set<java.lang.String> getPersistedStringSet(java.util.Set<java.lang.String>);
+    method public android.preference.PreferenceDataStore getPreferenceDataStore();
     method public android.preference.PreferenceManager getPreferenceManager();
     method public android.content.SharedPreferences getSharedPreferences();
     method public boolean getShouldDisableView();
@@ -30058,6 +30094,7 @@
     method public void setOnPreferenceClickListener(android.preference.Preference.OnPreferenceClickListener);
     method public void setOrder(int);
     method public void setPersistent(boolean);
+    method public void setPreferenceDataStore(android.preference.PreferenceDataStore);
     method public void setSelectable(boolean);
     method public void setShouldDisableView(boolean);
     method public void setSummary(java.lang.CharSequence);
@@ -30158,6 +30195,21 @@
     ctor public PreferenceCategory(android.content.Context);
   }
 
+  public abstract interface PreferenceDataStore {
+    method public default boolean getBoolean(java.lang.String, boolean);
+    method public default float getFloat(java.lang.String, float);
+    method public default int getInt(java.lang.String, int);
+    method public default long getLong(java.lang.String, long);
+    method public default java.lang.String getString(java.lang.String, java.lang.String);
+    method public default java.util.Set<java.lang.String> getStringSet(java.lang.String, java.util.Set<java.lang.String>);
+    method public default void putBoolean(java.lang.String, boolean);
+    method public default void putFloat(java.lang.String, float);
+    method public default void putInt(java.lang.String, int);
+    method public default void putLong(java.lang.String, long);
+    method public default void putString(java.lang.String, java.lang.String);
+    method public default void putStringSet(java.lang.String, java.util.Set<java.lang.String>);
+  }
+
   public abstract class PreferenceFragment extends android.app.Fragment {
     ctor public PreferenceFragment();
     method public void addPreferencesFromIntent(android.content.Intent);
@@ -30197,6 +30249,7 @@
     method public android.preference.Preference findPreference(java.lang.CharSequence);
     method public static android.content.SharedPreferences getDefaultSharedPreferences(android.content.Context);
     method public static java.lang.String getDefaultSharedPreferencesName(android.content.Context);
+    method public android.preference.PreferenceDataStore getPreferenceDataStore();
     method public android.content.SharedPreferences getSharedPreferences();
     method public int getSharedPreferencesMode();
     method public java.lang.String getSharedPreferencesName();
@@ -30204,6 +30257,7 @@
     method public boolean isStorageDeviceProtected();
     method public static void setDefaultValues(android.content.Context, int, boolean);
     method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
+    method public void setPreferenceDataStore(android.preference.PreferenceDataStore);
     method public void setSharedPreferencesMode(int);
     method public void setSharedPreferencesName(java.lang.String);
     method public void setStorageDefault();
@@ -37214,6 +37268,7 @@
     field public static final java.lang.String KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool";
     field public static final java.lang.String KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL = "ignore_sim_network_locked_events_bool";
     field public static final java.lang.String KEY_IMS_DTMF_TONE_DELAY_INT = "ims_dtmf_tone_delay_int";
+    field public static final java.lang.String KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL = "mdn_is_additional_voicemail_number_bool";
     field public static final java.lang.String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled";
     field public static final java.lang.String KEY_MMS_ALIAS_MAX_CHARS_INT = "aliasMaxChars";
     field public static final java.lang.String KEY_MMS_ALIAS_MIN_CHARS_INT = "aliasMinChars";
@@ -37402,6 +37457,7 @@
     method public int getAsuLevel();
     method public int getDbm();
     method public int getLevel();
+    method public int getTimingAdvance();
     method public int hashCode();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthGsm> CREATOR;
@@ -44337,7 +44393,7 @@
     field public static final int FLAG_ALT_FOCUSABLE_IM = 131072; // 0x20000
     field public static final deprecated int FLAG_BLUR_BEHIND = 4; // 0x4
     field public static final int FLAG_DIM_BEHIND = 2; // 0x2
-    field public static final int FLAG_DISMISS_KEYGUARD = 4194304; // 0x400000
+    field public static final deprecated int FLAG_DISMISS_KEYGUARD = 4194304; // 0x400000
     field public static final deprecated int FLAG_DITHER = 4096; // 0x1000
     field public static final int FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = -2147483648; // 0x80000000
     field public static final int FLAG_FORCE_NOT_FULLSCREEN = 2048; // 0x800
@@ -64198,7 +64254,7 @@
     method public abstract boolean eglCopyBuffers(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface, java.lang.Object);
     method public abstract javax.microedition.khronos.egl.EGLContext eglCreateContext(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, javax.microedition.khronos.egl.EGLContext, int[]);
     method public abstract javax.microedition.khronos.egl.EGLSurface eglCreatePbufferSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, int[]);
-    method public abstract javax.microedition.khronos.egl.EGLSurface eglCreatePixmapSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, java.lang.Object, int[]);
+    method public abstract deprecated javax.microedition.khronos.egl.EGLSurface eglCreatePixmapSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, java.lang.Object, int[]);
     method public abstract javax.microedition.khronos.egl.EGLSurface eglCreateWindowSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, java.lang.Object, int[]);
     method public abstract boolean eglDestroyContext(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLContext);
     method public abstract boolean eglDestroySurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface);
diff --git a/api/system-current.txt b/api/system-current.txt
index a71c0d3..f23c1fc 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -172,6 +172,7 @@
     field public static final java.lang.String READ_LOGS = "android.permission.READ_LOGS";
     field public static final java.lang.String READ_NETWORK_USAGE_HISTORY = "android.permission.READ_NETWORK_USAGE_HISTORY";
     field public static final java.lang.String READ_OEM_UNLOCK_STATE = "android.permission.READ_OEM_UNLOCK_STATE";
+    field public static final java.lang.String READ_PHONE_NUMBER = "android.permission.READ_PHONE_NUMBER";
     field public static final java.lang.String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE";
     field public static final java.lang.String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
     field public static final java.lang.String READ_SEARCH_INDEXABLES = "android.permission.READ_SEARCH_INDEXABLES";
@@ -900,10 +901,12 @@
     field public static final int layout_margin = 16842998; // 0x10100f6
     field public static final int layout_marginBottom = 16843002; // 0x10100fa
     field public static final int layout_marginEnd = 16843702; // 0x10103b6
+    field public static final int layout_marginHorizontal = 16844091; // 0x101053b
     field public static final int layout_marginLeft = 16842999; // 0x10100f7
     field public static final int layout_marginRight = 16843001; // 0x10100f9
     field public static final int layout_marginStart = 16843701; // 0x10103b5
     field public static final int layout_marginTop = 16843000; // 0x10100f8
+    field public static final int layout_marginVertical = 16844092; // 0x101053c
     field public static final int layout_row = 16843643; // 0x101037b
     field public static final int layout_rowSpan = 16843644; // 0x101037c
     field public static final int layout_rowWeight = 16843864; // 0x1010458
@@ -971,7 +974,7 @@
     field public static final int mediaRouteTypes = 16843694; // 0x10103ae
     field public static final int menuCategory = 16843230; // 0x10101de
     field public static final int mimeType = 16842790; // 0x1010026
-    field public static final int min = 16843367; // 0x1010267
+    field public static final int min = 16844089; // 0x1010539
     field public static final int minDate = 16843583; // 0x101033f
     field public static final int minEms = 16843098; // 0x101015a
     field public static final int minHeight = 16843072; // 0x1010140
@@ -1034,11 +1037,13 @@
     field public static final int padding = 16842965; // 0x10100d5
     field public static final int paddingBottom = 16842969; // 0x10100d9
     field public static final int paddingEnd = 16843700; // 0x10103b4
+    field public static final int paddingHorizontal = 16844093; // 0x101053d
     field public static final int paddingLeft = 16842966; // 0x10100d6
     field public static final int paddingMode = 16843863; // 0x1010457
     field public static final int paddingRight = 16842968; // 0x10100d8
     field public static final int paddingStart = 16843699; // 0x10103b3
     field public static final int paddingTop = 16842967; // 0x10100d7
+    field public static final int paddingVertical = 16844094; // 0x101053e
     field public static final int panelBackground = 16842846; // 0x101005e
     field public static final int panelColorBackground = 16842849; // 0x1010061
     field public static final int panelColorForeground = 16842848; // 0x1010060
@@ -1157,7 +1162,7 @@
     field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093
     field public static final int ringtoneType = 16843257; // 0x10101f9
     field public static final int rotation = 16843558; // 0x1010326
-    field public static final int rotationAnimation = 16843688; // 0x10103a8
+    field public static final int rotationAnimation = 16844090; // 0x101053a
     field public static final int rotationX = 16843559; // 0x1010327
     field public static final int rotationY = 16843560; // 0x1010328
     field public static final int roundIcon = 16844076; // 0x101052c
@@ -2913,9 +2918,14 @@
 
   public static class GestureDescription.StrokeDescription {
     ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long);
+    ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long, int, boolean);
+    method public int getContinuedStrokeId();
     method public long getDuration();
+    method public int getId();
     method public android.graphics.Path getPath();
     method public long getStartTime();
+    method public boolean isContinued();
+    field public static final int INVALID_STROKE_ID = -1; // 0xffffffff
   }
 
 }
@@ -4203,6 +4213,7 @@
     field public static final java.lang.String OPSTR_READ_CELL_BROADCASTS = "android:read_cell_broadcasts";
     field public static final java.lang.String OPSTR_READ_CONTACTS = "android:read_contacts";
     field public static final java.lang.String OPSTR_READ_EXTERNAL_STORAGE = "android:read_external_storage";
+    field public static final java.lang.String OPSTR_READ_PHONE_NUMBER = "android:read_phone_number";
     field public static final java.lang.String OPSTR_READ_PHONE_STATE = "android:read_phone_state";
     field public static final java.lang.String OPSTR_READ_SMS = "android:read_sms";
     field public static final java.lang.String OPSTR_RECEIVE_MMS = "android:receive_mms";
@@ -5519,12 +5530,14 @@
     ctor protected NotificationChannel(android.os.Parcel);
     method public boolean canBypassDnd();
     method public int describeContents();
+    method public void enableVibration(boolean);
     method public java.lang.String getId();
     method public int getImportance();
     method public int getLockscreenVisibility();
     method public java.lang.CharSequence getName();
     method public android.net.Uri getSound();
     method public int getUserLockedFields();
+    method public long[] getVibrationPattern();
     method public void lockFields(int);
     method public void populateFromXml(org.xmlpull.v1.XmlPullParser);
     method public void setBypassDnd(boolean);
@@ -5532,7 +5545,7 @@
     method public void setLights(boolean);
     method public void setLockscreenVisibility(int);
     method public void setSound(android.net.Uri);
-    method public void setVibration(boolean);
+    method public void setVibrationPattern(long[]);
     method public boolean shouldShowLights();
     method public boolean shouldVibrate();
     method public org.json.JSONObject toJson() throws org.json.JSONException;
@@ -5554,7 +5567,7 @@
     method public void cancel(int);
     method public void cancel(java.lang.String, int);
     method public void cancelAll();
-    method public void createNotificationChannel(android.app.NotificationChannel);
+    method public void createNotificationChannel(android.app.NotificationChannel, android.app.NotificationManager.OnNotificationChannelCreatedListener, android.os.Handler);
     method public void deleteNotificationChannel(java.lang.String);
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
     method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
@@ -5588,6 +5601,10 @@
     field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
   }
 
+  public static abstract interface NotificationManager.OnNotificationChannelCreatedListener {
+    method public abstract void onNotificationChannelCreated(android.app.NotificationChannel);
+  }
+
   public static class NotificationManager.Policy implements android.os.Parcelable {
     ctor public NotificationManager.Policy(int, int, int);
     ctor public NotificationManager.Policy(int, int, int, int);
@@ -6203,6 +6220,7 @@
     method public java.lang.String getDeviceOwner();
     method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
     method public java.lang.String getDeviceOwnerNameOnAnyUser();
+    method public java.lang.CharSequence getDeviceOwnerOrganizationName();
     method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
     method public int getKeyguardDisabledFeatures(android.content.ComponentName);
     method public java.lang.CharSequence getLongSupportMessage(android.content.ComponentName);
@@ -6250,6 +6268,7 @@
     method public boolean isAdminActive(android.content.ComponentName);
     method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
     method public boolean isCallerApplicationRestrictionsManagingPackage();
+    method public boolean isDeviceManaged();
     method public boolean isDeviceOwnerApp(java.lang.String);
     method public boolean isLockTaskPermitted(java.lang.String);
     method public boolean isManagedProfile(android.content.ComponentName);
@@ -6360,6 +6379,7 @@
     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_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";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME";
@@ -9162,6 +9182,7 @@
     field public static final java.lang.String CATEGORY_SELECTED_ALTERNATIVE = "android.intent.category.SELECTED_ALTERNATIVE";
     field public static final java.lang.String CATEGORY_TAB = "android.intent.category.TAB";
     field public static final java.lang.String CATEGORY_TEST = "android.intent.category.TEST";
+    field public static final java.lang.String CATEGORY_TYPED_OPENABLE = "android.intent.category.TYPED_OPENABLE";
     field public static final java.lang.String CATEGORY_UNIT_TEST = "android.intent.category.UNIT_TEST";
     field public static final java.lang.String CATEGORY_VOICE = "android.intent.category.VOICE";
     field public static final android.os.Parcelable.Creator<android.content.Intent> CREATOR;
@@ -12485,6 +12506,7 @@
     method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace, android.graphics.ColorSpace, android.graphics.ColorSpace.RenderIntent);
     method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace);
     method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace, android.graphics.ColorSpace.RenderIntent);
+    method public static android.graphics.ColorSpace.Renderer createRenderer();
     method public float[] fromXyz(float, float, float);
     method public abstract float[] fromXyz(float[]);
     method public static android.graphics.ColorSpace get(android.graphics.ColorSpace.Named);
@@ -12566,6 +12588,15 @@
     enum_constant public static final android.graphics.ColorSpace.RenderIntent SATURATION;
   }
 
+  public static class ColorSpace.Renderer {
+    method public android.graphics.ColorSpace.Renderer add(android.graphics.ColorSpace, int);
+    method public android.graphics.ColorSpace.Renderer add(android.graphics.ColorSpace, float, float, float, int);
+    method public android.graphics.ColorSpace.Renderer clip(boolean);
+    method public android.graphics.Bitmap render();
+    method public android.graphics.ColorSpace.Renderer showWhitePoint(boolean);
+    method public android.graphics.ColorSpace.Renderer size(int);
+  }
+
   public static class ColorSpace.Rgb extends android.graphics.ColorSpace {
     ctor public ColorSpace.Rgb(java.lang.String, float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator);
     ctor public ColorSpace.Rgb(java.lang.String, float[], float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator, float, float);
@@ -21742,8 +21773,8 @@
   }
 
   public class AudioTrack implements android.media.AudioRouting {
-    ctor public AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
-    ctor public AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
+    ctor public deprecated AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
+    ctor public deprecated AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
     ctor public AudioTrack(android.media.AudioAttributes, android.media.AudioFormat, int, int, int) throws java.lang.IllegalArgumentException;
     method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
     method public deprecated void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
@@ -23027,11 +23058,12 @@
     method public void prepareAsync() throws java.lang.IllegalStateException;
     method public void release();
     method public void reset();
+    method public void seekTo(int, int) throws java.lang.IllegalStateException;
     method public void seekTo(int) throws java.lang.IllegalStateException;
     method public void selectTrack(int) throws java.lang.IllegalStateException;
     method public void setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
     method public void setAudioSessionId(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public void setAudioStreamType(int);
+    method public deprecated void setAudioStreamType(int);
     method public void setAuxEffectSendLevel(float);
     method public void setDataSource(android.content.Context, android.net.Uri) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
     method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
@@ -23079,6 +23111,10 @@
     field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3
     field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc
     field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
+    field public static final int SEEK_CLOSEST = 3; // 0x3
+    field public static final int SEEK_CLOSEST_SYNC = 2; // 0x2
+    field public static final int SEEK_NEXT_SYNC = 1; // 0x1
+    field public static final int SEEK_PREVIOUS_SYNC = 0; // 0x0
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
   }
@@ -28069,7 +28105,7 @@
     method public static android.opengl.EGLContext eglCreateContext(android.opengl.EGLDisplay, android.opengl.EGLConfig, android.opengl.EGLContext, int[], int);
     method public static android.opengl.EGLSurface eglCreatePbufferFromClientBuffer(android.opengl.EGLDisplay, int, int, android.opengl.EGLConfig, int[], int);
     method public static android.opengl.EGLSurface eglCreatePbufferSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int[], int);
-    method public static android.opengl.EGLSurface eglCreatePixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int, int[], int);
+    method public static deprecated android.opengl.EGLSurface eglCreatePixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int, int[], int);
     method public static android.opengl.EGLSurface eglCreateWindowSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, java.lang.Object, int[], int);
     method public static boolean eglDestroyContext(android.opengl.EGLDisplay, android.opengl.EGLContext);
     method public static boolean eglDestroySurface(android.opengl.EGLDisplay, android.opengl.EGLSurface);
@@ -32267,6 +32303,7 @@
     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";
+    field public static final java.lang.String DISALLOW_BLUETOOTH = "no_bluetooth";
     field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
     field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
     field public static final java.lang.String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
@@ -32642,6 +32679,7 @@
     method protected long getPersistedLong(long);
     method protected java.lang.String getPersistedString(java.lang.String);
     method public java.util.Set<java.lang.String> getPersistedStringSet(java.util.Set<java.lang.String>);
+    method public android.preference.PreferenceDataStore getPreferenceDataStore();
     method public android.preference.PreferenceManager getPreferenceManager();
     method public android.content.SharedPreferences getSharedPreferences();
     method public boolean getShouldDisableView();
@@ -32691,6 +32729,7 @@
     method public void setOnPreferenceClickListener(android.preference.Preference.OnPreferenceClickListener);
     method public void setOrder(int);
     method public void setPersistent(boolean);
+    method public void setPreferenceDataStore(android.preference.PreferenceDataStore);
     method public void setSelectable(boolean);
     method public void setShouldDisableView(boolean);
     method public void setSummary(java.lang.CharSequence);
@@ -32791,6 +32830,21 @@
     ctor public PreferenceCategory(android.content.Context);
   }
 
+  public abstract interface PreferenceDataStore {
+    method public default boolean getBoolean(java.lang.String, boolean);
+    method public default float getFloat(java.lang.String, float);
+    method public default int getInt(java.lang.String, int);
+    method public default long getLong(java.lang.String, long);
+    method public default java.lang.String getString(java.lang.String, java.lang.String);
+    method public default java.util.Set<java.lang.String> getStringSet(java.lang.String, java.util.Set<java.lang.String>);
+    method public default void putBoolean(java.lang.String, boolean);
+    method public default void putFloat(java.lang.String, float);
+    method public default void putInt(java.lang.String, int);
+    method public default void putLong(java.lang.String, long);
+    method public default void putString(java.lang.String, java.lang.String);
+    method public default void putStringSet(java.lang.String, java.util.Set<java.lang.String>);
+  }
+
   public abstract class PreferenceFragment extends android.app.Fragment {
     ctor public PreferenceFragment();
     method public void addPreferencesFromIntent(android.content.Intent);
@@ -32830,6 +32884,7 @@
     method public android.preference.Preference findPreference(java.lang.CharSequence);
     method public static android.content.SharedPreferences getDefaultSharedPreferences(android.content.Context);
     method public static java.lang.String getDefaultSharedPreferencesName(android.content.Context);
+    method public android.preference.PreferenceDataStore getPreferenceDataStore();
     method public android.content.SharedPreferences getSharedPreferences();
     method public int getSharedPreferencesMode();
     method public java.lang.String getSharedPreferencesName();
@@ -32838,6 +32893,7 @@
     method public boolean isStorageDeviceProtected();
     method public static void setDefaultValues(android.content.Context, int, boolean);
     method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
+    method public void setPreferenceDataStore(android.preference.PreferenceDataStore);
     method public void setSharedPreferencesMode(int);
     method public void setSharedPreferencesName(java.lang.String);
     method public void setStorageCredentialProtected();
@@ -35590,6 +35646,7 @@
     field public static final int WIFI_SLEEP_POLICY_DEFAULT = 0; // 0x0
     field public static final int WIFI_SLEEP_POLICY_NEVER = 2; // 0x2
     field public static final int WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = 1; // 0x1
+    field public static final java.lang.String WIFI_WAKEUP_ENABLED = "wifi_wakeup_enabled";
     field public static final java.lang.String WIFI_WATCHDOG_ON = "wifi_watchdog_on";
     field public static final java.lang.String WINDOW_ANIMATION_SCALE = "window_animation_scale";
   }
@@ -37991,19 +38048,7 @@
 
 package android.service.persistentdata {
 
-  public abstract interface IPersistentDataBlockService implements android.os.IInterface {
-    method public abstract int getDataBlockSize() throws android.os.RemoteException;
-    method public abstract int getFlashLockState() throws android.os.RemoteException;
-    method public abstract long getMaximumDataBlockSize() throws android.os.RemoteException;
-    method public abstract boolean getOemUnlockEnabled() throws android.os.RemoteException;
-    method public abstract byte[] read() throws android.os.RemoteException;
-    method public abstract void setOemUnlockEnabled(boolean) throws android.os.RemoteException;
-    method public abstract void wipe() throws android.os.RemoteException;
-    method public abstract int write(byte[]) throws android.os.RemoteException;
-  }
-
   public class PersistentDataBlockManager {
-    ctor public PersistentDataBlockManager(android.service.persistentdata.IPersistentDataBlockService);
     method public int getDataBlockSize();
     method public int getFlashLockState();
     method public long getMaximumDataBlockSize();
@@ -40294,6 +40339,7 @@
     field public static final java.lang.String KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool";
     field public static final java.lang.String KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL = "ignore_sim_network_locked_events_bool";
     field public static final java.lang.String KEY_IMS_DTMF_TONE_DELAY_INT = "ims_dtmf_tone_delay_int";
+    field public static final java.lang.String KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL = "mdn_is_additional_voicemail_number_bool";
     field public static final java.lang.String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled";
     field public static final java.lang.String KEY_MMS_ALIAS_MAX_CHARS_INT = "aliasMaxChars";
     field public static final java.lang.String KEY_MMS_ALIAS_MIN_CHARS_INT = "aliasMinChars";
@@ -40482,6 +40528,7 @@
     method public int getAsuLevel();
     method public int getDbm();
     method public int getLevel();
+    method public int getTimingAdvance();
     method public int hashCode();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthGsm> CREATOR;
@@ -47502,7 +47549,7 @@
     field public static final int FLAG_ALT_FOCUSABLE_IM = 131072; // 0x20000
     field public static final deprecated int FLAG_BLUR_BEHIND = 4; // 0x4
     field public static final int FLAG_DIM_BEHIND = 2; // 0x2
-    field public static final int FLAG_DISMISS_KEYGUARD = 4194304; // 0x400000
+    field public static final deprecated int FLAG_DISMISS_KEYGUARD = 4194304; // 0x400000
     field public static final deprecated int FLAG_DITHER = 4096; // 0x1000
     field public static final int FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = -2147483648; // 0x80000000
     field public static final int FLAG_FORCE_NOT_FULLSCREEN = 2048; // 0x800
@@ -67719,7 +67766,7 @@
     method public abstract boolean eglCopyBuffers(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface, java.lang.Object);
     method public abstract javax.microedition.khronos.egl.EGLContext eglCreateContext(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, javax.microedition.khronos.egl.EGLContext, int[]);
     method public abstract javax.microedition.khronos.egl.EGLSurface eglCreatePbufferSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, int[]);
-    method public abstract javax.microedition.khronos.egl.EGLSurface eglCreatePixmapSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, java.lang.Object, int[]);
+    method public abstract deprecated javax.microedition.khronos.egl.EGLSurface eglCreatePixmapSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, java.lang.Object, int[]);
     method public abstract javax.microedition.khronos.egl.EGLSurface eglCreateWindowSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, java.lang.Object, int[]);
     method public abstract boolean eglDestroyContext(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLContext);
     method public abstract boolean eglDestroySurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface);
diff --git a/api/test-current.txt b/api/test-current.txt
index b44715b..810680d 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -99,6 +99,7 @@
     field public static final java.lang.String READ_FRAME_BUFFER = "android.permission.READ_FRAME_BUFFER";
     field public static final deprecated java.lang.String READ_INPUT_STATE = "android.permission.READ_INPUT_STATE";
     field public static final java.lang.String READ_LOGS = "android.permission.READ_LOGS";
+    field public static final java.lang.String READ_PHONE_NUMBER = "android.permission.READ_PHONE_NUMBER";
     field public static final java.lang.String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE";
     field public static final java.lang.String READ_SMS = "android.permission.READ_SMS";
     field public static final java.lang.String READ_SYNC_SETTINGS = "android.permission.READ_SYNC_SETTINGS";
@@ -793,10 +794,12 @@
     field public static final int layout_margin = 16842998; // 0x10100f6
     field public static final int layout_marginBottom = 16843002; // 0x10100fa
     field public static final int layout_marginEnd = 16843702; // 0x10103b6
+    field public static final int layout_marginHorizontal = 16844091; // 0x101053b
     field public static final int layout_marginLeft = 16842999; // 0x10100f7
     field public static final int layout_marginRight = 16843001; // 0x10100f9
     field public static final int layout_marginStart = 16843701; // 0x10103b5
     field public static final int layout_marginTop = 16843000; // 0x10100f8
+    field public static final int layout_marginVertical = 16844092; // 0x101053c
     field public static final int layout_row = 16843643; // 0x101037b
     field public static final int layout_rowSpan = 16843644; // 0x101037c
     field public static final int layout_rowWeight = 16843864; // 0x1010458
@@ -864,7 +867,7 @@
     field public static final int mediaRouteTypes = 16843694; // 0x10103ae
     field public static final int menuCategory = 16843230; // 0x10101de
     field public static final int mimeType = 16842790; // 0x1010026
-    field public static final int min = 16843367; // 0x1010267
+    field public static final int min = 16844089; // 0x1010539
     field public static final int minDate = 16843583; // 0x101033f
     field public static final int minEms = 16843098; // 0x101015a
     field public static final int minHeight = 16843072; // 0x1010140
@@ -927,11 +930,13 @@
     field public static final int padding = 16842965; // 0x10100d5
     field public static final int paddingBottom = 16842969; // 0x10100d9
     field public static final int paddingEnd = 16843700; // 0x10103b4
+    field public static final int paddingHorizontal = 16844093; // 0x101053d
     field public static final int paddingLeft = 16842966; // 0x10100d6
     field public static final int paddingMode = 16843863; // 0x1010457
     field public static final int paddingRight = 16842968; // 0x10100d8
     field public static final int paddingStart = 16843699; // 0x10103b3
     field public static final int paddingTop = 16842967; // 0x10100d7
+    field public static final int paddingVertical = 16844094; // 0x101053e
     field public static final int panelBackground = 16842846; // 0x101005e
     field public static final int panelColorBackground = 16842849; // 0x1010061
     field public static final int panelColorForeground = 16842848; // 0x1010060
@@ -1050,7 +1055,7 @@
     field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093
     field public static final int ringtoneType = 16843257; // 0x10101f9
     field public static final int rotation = 16843558; // 0x1010326
-    field public static final int rotationAnimation = 16843688; // 0x10103a8
+    field public static final int rotationAnimation = 16844090; // 0x101053a
     field public static final int rotationX = 16843559; // 0x1010327
     field public static final int rotationY = 16843560; // 0x1010328
     field public static final int roundIcon = 16844076; // 0x101052c
@@ -2799,9 +2804,14 @@
 
   public static class GestureDescription.StrokeDescription {
     ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long);
+    ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long, int, boolean);
+    method public int getContinuedStrokeId();
     method public long getDuration();
+    method public int getId();
     method public android.graphics.Path getPath();
     method public long getStartTime();
+    method public boolean isContinued();
+    field public static final int INVALID_STROKE_ID = -1; // 0xffffffff
   }
 
 }
@@ -4077,6 +4087,7 @@
     field public static final java.lang.String OPSTR_READ_CELL_BROADCASTS = "android:read_cell_broadcasts";
     field public static final java.lang.String OPSTR_READ_CONTACTS = "android:read_contacts";
     field public static final java.lang.String OPSTR_READ_EXTERNAL_STORAGE = "android:read_external_storage";
+    field public static final java.lang.String OPSTR_READ_PHONE_NUMBER = "android:read_phone_number";
     field public static final java.lang.String OPSTR_READ_PHONE_STATE = "android:read_phone_state";
     field public static final java.lang.String OPSTR_READ_SMS = "android:read_sms";
     field public static final java.lang.String OPSTR_RECEIVE_MMS = "android:receive_mms";
@@ -5373,17 +5384,19 @@
     ctor protected NotificationChannel(android.os.Parcel);
     method public boolean canBypassDnd();
     method public int describeContents();
+    method public void enableVibration(boolean);
     method public java.lang.String getId();
     method public int getImportance();
     method public int getLockscreenVisibility();
     method public java.lang.CharSequence getName();
     method public android.net.Uri getSound();
+    method public long[] getVibrationPattern();
     method public void setBypassDnd(boolean);
     method public void setImportance(int);
     method public void setLights(boolean);
     method public void setLockscreenVisibility(int);
     method public void setSound(android.net.Uri);
-    method public void setVibration(boolean);
+    method public void setVibrationPattern(long[]);
     method public boolean shouldShowLights();
     method public boolean shouldVibrate();
     method public void writeToParcel(android.os.Parcel, int);
@@ -5397,7 +5410,7 @@
     method public void cancel(int);
     method public void cancel(java.lang.String, int);
     method public void cancelAll();
-    method public void createNotificationChannel(android.app.NotificationChannel);
+    method public void createNotificationChannel(android.app.NotificationChannel, android.app.NotificationManager.OnNotificationChannelCreatedListener, android.os.Handler);
     method public void deleteNotificationChannel(java.lang.String);
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
     method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
@@ -5432,6 +5445,10 @@
     field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
   }
 
+  public static abstract interface NotificationManager.OnNotificationChannelCreatedListener {
+    method public abstract void onNotificationChannelCreated(android.app.NotificationChannel);
+  }
+
   public static class NotificationManager.Policy implements android.os.Parcelable {
     ctor public NotificationManager.Policy(int, int, int);
     ctor public NotificationManager.Policy(int, int, int, int);
@@ -6044,6 +6061,7 @@
     method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName);
     method public int getCurrentFailedPasswordAttempts();
     method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
+    method public java.lang.CharSequence getDeviceOwnerOrganizationName();
     method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
     method public int getKeyguardDisabledFeatures(android.content.ComponentName);
     method public long getLastBugReportRequestTime();
@@ -6089,6 +6107,7 @@
     method public boolean isAdminActive(android.content.ComponentName);
     method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
     method public boolean isCallerApplicationRestrictionsManagingPackage();
+    method public boolean isDeviceManaged();
     method public boolean isDeviceOwnerApp(java.lang.String);
     method public boolean isLockTaskPermitted(java.lang.String);
     method public boolean isManagedProfile(android.content.ComponentName);
@@ -6193,6 +6212,7 @@
     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_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";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME";
@@ -8827,6 +8847,7 @@
     field public static final java.lang.String CATEGORY_SELECTED_ALTERNATIVE = "android.intent.category.SELECTED_ALTERNATIVE";
     field public static final java.lang.String CATEGORY_TAB = "android.intent.category.TAB";
     field public static final java.lang.String CATEGORY_TEST = "android.intent.category.TEST";
+    field public static final java.lang.String CATEGORY_TYPED_OPENABLE = "android.intent.category.TYPED_OPENABLE";
     field public static final java.lang.String CATEGORY_UNIT_TEST = "android.intent.category.UNIT_TEST";
     field public static final java.lang.String CATEGORY_VOICE = "android.intent.category.VOICE";
     field public static final android.os.Parcelable.Creator<android.content.Intent> CREATOR;
@@ -12031,6 +12052,7 @@
     method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace, android.graphics.ColorSpace, android.graphics.ColorSpace.RenderIntent);
     method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace);
     method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace, android.graphics.ColorSpace.RenderIntent);
+    method public static android.graphics.ColorSpace.Renderer createRenderer();
     method public float[] fromXyz(float, float, float);
     method public abstract float[] fromXyz(float[]);
     method public static android.graphics.ColorSpace get(android.graphics.ColorSpace.Named);
@@ -12112,6 +12134,15 @@
     enum_constant public static final android.graphics.ColorSpace.RenderIntent SATURATION;
   }
 
+  public static class ColorSpace.Renderer {
+    method public android.graphics.ColorSpace.Renderer add(android.graphics.ColorSpace, int);
+    method public android.graphics.ColorSpace.Renderer add(android.graphics.ColorSpace, float, float, float, int);
+    method public android.graphics.ColorSpace.Renderer clip(boolean);
+    method public android.graphics.Bitmap render();
+    method public android.graphics.ColorSpace.Renderer showWhitePoint(boolean);
+    method public android.graphics.ColorSpace.Renderer size(int);
+  }
+
   public static class ColorSpace.Rgb extends android.graphics.ColorSpace {
     ctor public ColorSpace.Rgb(java.lang.String, float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator);
     ctor public ColorSpace.Rgb(java.lang.String, float[], float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator, float, float);
@@ -20262,8 +20293,8 @@
   }
 
   public class AudioTrack implements android.media.AudioRouting {
-    ctor public AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
-    ctor public AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
+    ctor public deprecated AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
+    ctor public deprecated AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
     ctor public AudioTrack(android.media.AudioAttributes, android.media.AudioFormat, int, int, int) throws java.lang.IllegalArgumentException;
     method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
     method public deprecated void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
@@ -21547,11 +21578,12 @@
     method public void prepareAsync() throws java.lang.IllegalStateException;
     method public void release();
     method public void reset();
+    method public void seekTo(int, int) throws java.lang.IllegalStateException;
     method public void seekTo(int) throws java.lang.IllegalStateException;
     method public void selectTrack(int) throws java.lang.IllegalStateException;
     method public void setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
     method public void setAudioSessionId(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public void setAudioStreamType(int);
+    method public deprecated void setAudioStreamType(int);
     method public void setAuxEffectSendLevel(float);
     method public void setDataSource(android.content.Context, android.net.Uri) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
     method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
@@ -21599,6 +21631,10 @@
     field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3
     field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc
     field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
+    field public static final int SEEK_CLOSEST = 3; // 0x3
+    field public static final int SEEK_CLOSEST_SYNC = 2; // 0x2
+    field public static final int SEEK_NEXT_SYNC = 1; // 0x1
+    field public static final int SEEK_PREVIOUS_SYNC = 0; // 0x0
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
   }
@@ -25629,7 +25665,7 @@
     method public static android.opengl.EGLContext eglCreateContext(android.opengl.EGLDisplay, android.opengl.EGLConfig, android.opengl.EGLContext, int[], int);
     method public static android.opengl.EGLSurface eglCreatePbufferFromClientBuffer(android.opengl.EGLDisplay, int, int, android.opengl.EGLConfig, int[], int);
     method public static android.opengl.EGLSurface eglCreatePbufferSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int[], int);
-    method public static android.opengl.EGLSurface eglCreatePixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int, int[], int);
+    method public static deprecated android.opengl.EGLSurface eglCreatePixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int, int[], int);
     method public static android.opengl.EGLSurface eglCreateWindowSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, java.lang.Object, int[], int);
     method public static boolean eglDestroyContext(android.opengl.EGLDisplay, android.opengl.EGLContext);
     method public static boolean eglDestroySurface(android.opengl.EGLDisplay, android.opengl.EGLSurface);
@@ -29741,6 +29777,7 @@
     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";
+    field public static final java.lang.String DISALLOW_BLUETOOTH = "no_bluetooth";
     field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
     field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
     field public static final java.lang.String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
@@ -30096,6 +30133,7 @@
     method protected long getPersistedLong(long);
     method protected java.lang.String getPersistedString(java.lang.String);
     method public java.util.Set<java.lang.String> getPersistedStringSet(java.util.Set<java.lang.String>);
+    method public android.preference.PreferenceDataStore getPreferenceDataStore();
     method public android.preference.PreferenceManager getPreferenceManager();
     method public android.content.SharedPreferences getSharedPreferences();
     method public boolean getShouldDisableView();
@@ -30145,6 +30183,7 @@
     method public void setOnPreferenceClickListener(android.preference.Preference.OnPreferenceClickListener);
     method public void setOrder(int);
     method public void setPersistent(boolean);
+    method public void setPreferenceDataStore(android.preference.PreferenceDataStore);
     method public void setSelectable(boolean);
     method public void setShouldDisableView(boolean);
     method public void setSummary(java.lang.CharSequence);
@@ -30245,6 +30284,21 @@
     ctor public PreferenceCategory(android.content.Context);
   }
 
+  public abstract interface PreferenceDataStore {
+    method public default boolean getBoolean(java.lang.String, boolean);
+    method public default float getFloat(java.lang.String, float);
+    method public default int getInt(java.lang.String, int);
+    method public default long getLong(java.lang.String, long);
+    method public default java.lang.String getString(java.lang.String, java.lang.String);
+    method public default java.util.Set<java.lang.String> getStringSet(java.lang.String, java.util.Set<java.lang.String>);
+    method public default void putBoolean(java.lang.String, boolean);
+    method public default void putFloat(java.lang.String, float);
+    method public default void putInt(java.lang.String, int);
+    method public default void putLong(java.lang.String, long);
+    method public default void putString(java.lang.String, java.lang.String);
+    method public default void putStringSet(java.lang.String, java.util.Set<java.lang.String>);
+  }
+
   public abstract class PreferenceFragment extends android.app.Fragment {
     ctor public PreferenceFragment();
     method public void addPreferencesFromIntent(android.content.Intent);
@@ -30284,6 +30338,7 @@
     method public android.preference.Preference findPreference(java.lang.CharSequence);
     method public static android.content.SharedPreferences getDefaultSharedPreferences(android.content.Context);
     method public static java.lang.String getDefaultSharedPreferencesName(android.content.Context);
+    method public android.preference.PreferenceDataStore getPreferenceDataStore();
     method public android.content.SharedPreferences getSharedPreferences();
     method public int getSharedPreferencesMode();
     method public java.lang.String getSharedPreferencesName();
@@ -30291,6 +30346,7 @@
     method public boolean isStorageDeviceProtected();
     method public static void setDefaultValues(android.content.Context, int, boolean);
     method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
+    method public void setPreferenceDataStore(android.preference.PreferenceDataStore);
     method public void setSharedPreferencesMode(int);
     method public void setSharedPreferencesName(java.lang.String);
     method public void setStorageDefault();
@@ -37308,6 +37364,7 @@
     field public static final java.lang.String KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool";
     field public static final java.lang.String KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL = "ignore_sim_network_locked_events_bool";
     field public static final java.lang.String KEY_IMS_DTMF_TONE_DELAY_INT = "ims_dtmf_tone_delay_int";
+    field public static final java.lang.String KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL = "mdn_is_additional_voicemail_number_bool";
     field public static final java.lang.String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled";
     field public static final java.lang.String KEY_MMS_ALIAS_MAX_CHARS_INT = "aliasMaxChars";
     field public static final java.lang.String KEY_MMS_ALIAS_MIN_CHARS_INT = "aliasMinChars";
@@ -37496,6 +37553,7 @@
     method public int getAsuLevel();
     method public int getDbm();
     method public int getLevel();
+    method public int getTimingAdvance();
     method public int hashCode();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthGsm> CREATOR;
@@ -44591,7 +44649,7 @@
     field public static final int FLAG_ALT_FOCUSABLE_IM = 131072; // 0x20000
     field public static final deprecated int FLAG_BLUR_BEHIND = 4; // 0x4
     field public static final int FLAG_DIM_BEHIND = 2; // 0x2
-    field public static final int FLAG_DISMISS_KEYGUARD = 4194304; // 0x400000
+    field public static final deprecated int FLAG_DISMISS_KEYGUARD = 4194304; // 0x400000
     field public static final deprecated int FLAG_DITHER = 4096; // 0x1000
     field public static final int FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = -2147483648; // 0x80000000
     field public static final int FLAG_FORCE_NOT_FULLSCREEN = 2048; // 0x800
@@ -64468,7 +64526,7 @@
     method public abstract boolean eglCopyBuffers(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface, java.lang.Object);
     method public abstract javax.microedition.khronos.egl.EGLContext eglCreateContext(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, javax.microedition.khronos.egl.EGLContext, int[]);
     method public abstract javax.microedition.khronos.egl.EGLSurface eglCreatePbufferSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, int[]);
-    method public abstract javax.microedition.khronos.egl.EGLSurface eglCreatePixmapSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, java.lang.Object, int[]);
+    method public abstract deprecated javax.microedition.khronos.egl.EGLSurface eglCreatePixmapSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, java.lang.Object, int[]);
     method public abstract javax.microedition.khronos.egl.EGLSurface eglCreateWindowSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, java.lang.Object, int[]);
     method public abstract boolean eglDestroyContext(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLContext);
     method public abstract boolean eglDestroySurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface);
diff --git a/cmds/app_process/Android.mk b/cmds/app_process/Android.mk
index e18de8e..eaad3a7 100644
--- a/cmds/app_process/Android.mk
+++ b/cmds/app_process/Android.mk
@@ -1,78 +1,67 @@
 LOCAL_PATH:= $(call my-dir)
 
+app_process_common_shared_libs := \
+    libandroid_runtime \
+    libbinder \
+    libcutils \
+    libdl \
+    liblog \
+    libnativeloader \
+    libutils \
+
 # This is a list of libraries that need to be included in order to avoid
 # bad apps. This prevents a library from having a mismatch when resolving
 # new/delete from an app shared library.
 # See b/21032018 for more details.
-app_process_common_shared_libs := \
+app_process_common_shared_libs += \
     libwilhelm \
 
+app_process_common_static_libs := \
+    libsigchain \
+
+app_process_src_files := \
+    app_main.cpp \
+
+app_process_cflags := \
+    -Wall -Werror -Wunused -Wunreachable-code
+
+app_process_ldflags_32 := \
+    -Wl,--version-script,art/sigchainlib/version-script32.txt -Wl,--export-dynamic
+app_process_ldflags_64 := \
+    -Wl,--version-script,art/sigchainlib/version-script64.txt -Wl,--export-dynamic
+
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:= \
-    app_main.cpp
+LOCAL_SRC_FILES:= $(app_process_src_files)
 
-LOCAL_LDFLAGS_32 := -Wl,--version-script,art/sigchainlib/version-script32.txt -Wl,--export-dynamic
-LOCAL_LDFLAGS_64 := -Wl,--version-script,art/sigchainlib/version-script64.txt -Wl,--export-dynamic
+LOCAL_LDFLAGS_32 := $(app_process_ldflags_32)
+LOCAL_LDFLAGS_64 := $(app_process_ldflags_64)
 
-LOCAL_SHARED_LIBRARIES := \
-    libdl \
-    libcutils \
-    libutils \
-    liblog \
-    libbinder \
-    libnativeloader \
-    libandroid_runtime \
-    $(app_process_common_shared_libs) \
+LOCAL_SHARED_LIBRARIES := $(app_process_common_shared_libs)
 
-LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
+LOCAL_WHOLE_STATIC_LIBRARIES := $(app_process_common_static_libs)
 
 LOCAL_MODULE:= app_process
 LOCAL_MULTILIB := both
 LOCAL_MODULE_STEM_32 := app_process32
 LOCAL_MODULE_STEM_64 := app_process64
 
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+LOCAL_CFLAGS += $(app_process_cflags)
+
+# In SANITIZE_LITE mode, we create the sanitized binary in a separate location (but reuse
+# the same module). Using the same module also works around an issue with make: binaries
+# that depend on sanitized libraries will be relinked, even if they set LOCAL_SANITIZE := never.
+#
+# Also pull in the asanwrapper helper.
+ifeq ($(SANITIZE_LITE),true)
+LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)/asan
+LOCAL_REQUIRED_MODULES := asanwrapper
+endif
 
 include $(BUILD_EXECUTABLE)
 
 # Create a symlink from app_process to app_process32 or 64
 # depending on the target configuration.
+ifneq ($(SANITIZE_LITE),true)
 include  $(BUILD_SYSTEM)/executable_prefer_symlink.mk
-
-# Build a variant of app_process binary linked with ASan runtime.
-# ARM-only at the moment.
-ifeq ($(TARGET_ARCH),arm)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-    app_main.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    libutils \
-    liblog \
-    libbinder \
-    libandroid_runtime \
-    $(app_process_common_shared_libs) \
-
-LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
-
-LOCAL_LDFLAGS := -ldl
-LOCAL_LDFLAGS_32 := -Wl,--version-script,art/sigchainlib/version-script32.txt -Wl,--export-dynamic
-LOCAL_LDFLAGS_64 := -Wl,--version-script,art/sigchainlib/version-script64.txt -Wl,--export-dynamic
-
-LOCAL_MODULE := app_process__asan
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := app_process32
-LOCAL_MODULE_STEM_64 := app_process64
-
-LOCAL_SANITIZE := address
-LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)/asan
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-
-include $(BUILD_EXECUTABLE)
-
-endif # ifeq($(TARGET_ARCH),arm)
+endif
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index 4291c77..db3772d 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -92,6 +92,8 @@
             runSetEmulateFbe();
         } else if ("get-fbe-mode".equals(op)) {
             runGetFbeMode();
+        } else if ("fstrim".equals(op)) {
+            runFstrim();
         } else {
             throw new IllegalArgumentException();
         }
@@ -210,7 +212,7 @@
         mSm.benchmark(volId);
     }
 
-    public void runForget() throws RemoteException{
+    public void runForget() throws RemoteException {
         final String fsUuid = nextArg();
         if ("all".equals(fsUuid)) {
             mSm.forgetAllVolumes();
@@ -219,6 +221,10 @@
         }
     }
 
+    public void runFstrim() throws RemoteException {
+        mSm.fstrim(0);
+    }
+
     private String nextArg() {
         if (mNextArg >= mArgs.length) {
             return null;
@@ -240,6 +246,7 @@
         System.err.println("       sm unmount VOLUME");
         System.err.println("       sm format VOLUME");
         System.err.println("       sm benchmark VOLUME");
+        System.err.println("       sm fstrim");
         System.err.println("");
         System.err.println("       sm forget [UUID|all]");
         System.err.println("");
diff --git a/core/java/android/accessibilityservice/GestureDescription.java b/core/java/android/accessibilityservice/GestureDescription.java
index d9b03fa..c9da152 100644
--- a/core/java/android/accessibilityservice/GestureDescription.java
+++ b/core/java/android/accessibilityservice/GestureDescription.java
@@ -23,10 +23,6 @@
 import android.graphics.RectF;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.view.InputDevice;
-import android.view.MotionEvent;
-import android.view.MotionEvent.PointerCoords;
-import android.view.MotionEvent.PointerProperties;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -128,9 +124,14 @@
         for (int i = 0; i < mStrokes.size(); i++) {
             StrokeDescription strokeDescription = mStrokes.get(i);
             if (strokeDescription.hasPointForTime(time)) {
-                touchPoints[numPointsFound].mPathIndex = i;
-                touchPoints[numPointsFound].mIsStartOfPath = (time == strokeDescription.mStartTime);
-                touchPoints[numPointsFound].mIsEndOfPath = (time == strokeDescription.mEndTime);
+                touchPoints[numPointsFound].mStrokeId = strokeDescription.getId();
+                touchPoints[numPointsFound].mContinuedStrokeId =
+                        strokeDescription.getContinuedStrokeId();
+                touchPoints[numPointsFound].mIsStartOfPath =
+                        (strokeDescription.getContinuedStrokeId() < 0)
+                                && (time == strokeDescription.mStartTime);
+                touchPoints[numPointsFound].mIsEndOfPath = !strokeDescription.isContinued()
+                        && (time == strokeDescription.mEndTime);
                 strokeDescription.getPosForTime(time, mTempPos);
                 touchPoints[numPointsFound].mX = Math.round(mTempPos[0]);
                 touchPoints[numPointsFound].mY = Math.round(mTempPos[1]);
@@ -196,6 +197,10 @@
      * Immutable description of stroke that can be part of a gesture.
      */
     public static class StrokeDescription {
+        public static final int INVALID_STROKE_ID = -1;
+
+        static int sIdCounter;
+
         Path mPath;
         long mStartTime;
         long mEndTime;
@@ -203,6 +208,9 @@
         private PathMeasure mPathMeasure;
         // The tap location is only set for zero-length paths
         float[] mTapLocation;
+        int mId;
+        boolean mContinued;
+        int mContinuedStrokeId;
 
         /**
          * @param path The path to follow. Must have exactly one contour. The bounds of the path
@@ -216,6 +224,32 @@
         public StrokeDescription(@NonNull Path path,
                 @IntRange(from = 0) long startTime,
                 @IntRange(from = 0) long duration) {
+            this(path, startTime, duration, INVALID_STROKE_ID, false);
+        }
+
+        /**
+         * @param path The path to follow. Must have exactly one contour. The bounds of the path
+         * must not be negative. The path must not be empty. If the path has zero length
+         * (for example, a single {@code moveTo()}), the stroke is a touch that doesn't move.
+         * @param startTime The time, in milliseconds, from the time the gesture starts to the
+         * time the stroke should start. Must not be negative.
+         * @param duration The duration, in milliseconds, the stroke takes to traverse the path.
+         * Must be positive.
+         * @param continuedStrokeId The ID of the stroke that this stroke continues, or
+         * {@link #INVALID_STROKE_ID} if it continues no stroke. The stroke it
+         * continues must have its isContinued flag set to {@code true} and must be in the
+         * gesture dispatched immediately before the one containing this stroke.
+         * @param isContinued {@code true} if this stroke will be continued by one in the
+         * next gesture {@code false} otherwise. Continued strokes keep their pointers down when
+         * the gesture completes.
+         */
+        public StrokeDescription(@NonNull Path path,
+                @IntRange(from = 0) long startTime,
+                @IntRange(from = 0) long duration,
+                @IntRange(from = 0) int continuedStrokeId,
+                boolean isContinued) {
+            mContinued = isContinued;
+            mContinuedStrokeId = continuedStrokeId;
             if (duration <= 0) {
                 throw new IllegalArgumentException("Duration must be positive");
             }
@@ -252,6 +286,7 @@
             mStartTime = startTime;
             mEndTime = startTime + duration;
             mTimeToLengthConversion = getLength() / duration;
+            mId = sIdCounter++;
         }
 
         /**
@@ -281,6 +316,34 @@
             return mEndTime - mStartTime;
         }
 
+        /**
+         * Get the stroke's ID. The ID is used when a stroke is to be continued by another
+         * stroke in a future gesture.
+         *
+         * @return the ID of this stroke
+         */
+        public int getId() {
+            return mId;
+        }
+
+        /**
+         * Check if this stroke is marked to continue in the next gesture.
+         *
+         * @return {@code true} if the stroke is to be continued.
+         */
+        public boolean isContinued() {
+            return mContinued;
+        }
+
+        /**
+         * Get the ID of the stroke that this one will continue.
+         *
+         * @return The ID of the stroke that this stroke continues, or 0 if no such stroke exists.
+         */
+        public int getContinuedStrokeId() {
+            return mContinuedStrokeId;
+        }
+
         float getLength() {
             return mPathMeasure.getLength();
         }
@@ -314,11 +377,12 @@
         private static final int FLAG_IS_START_OF_PATH = 0x01;
         private static final int FLAG_IS_END_OF_PATH = 0x02;
 
-        int mPathIndex;
-        boolean mIsStartOfPath;
-        boolean mIsEndOfPath;
-        float mX;
-        float mY;
+        public int mStrokeId;
+        public int mContinuedStrokeId;
+        public boolean mIsStartOfPath;
+        public boolean mIsEndOfPath;
+        public float mX;
+        public float mY;
 
         public TouchPoint() {
         }
@@ -328,7 +392,8 @@
         }
 
         public TouchPoint(Parcel parcel) {
-            mPathIndex = parcel.readInt();
+            mStrokeId = parcel.readInt();
+            mContinuedStrokeId = parcel.readInt();
             int startEnd = parcel.readInt();
             mIsStartOfPath = (startEnd & FLAG_IS_START_OF_PATH) != 0;
             mIsEndOfPath = (startEnd & FLAG_IS_END_OF_PATH) != 0;
@@ -336,8 +401,9 @@
             mY = parcel.readFloat();
         }
 
-        void copyFrom(TouchPoint other) {
-            mPathIndex = other.mPathIndex;
+        public void copyFrom(TouchPoint other) {
+            mStrokeId = other.mStrokeId;
+            mContinuedStrokeId = other.mContinuedStrokeId;
             mIsStartOfPath = other.mIsStartOfPath;
             mIsEndOfPath = other.mIsEndOfPath;
             mX = other.mX;
@@ -351,7 +417,8 @@
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(mPathIndex);
+            dest.writeInt(mStrokeId);
+            dest.writeInt(mContinuedStrokeId);
             int startEnd = mIsStartOfPath ? FLAG_IS_START_OF_PATH : 0;
             startEnd |= mIsEndOfPath ? FLAG_IS_END_OF_PATH : 0;
             dest.writeInt(startEnd);
@@ -426,30 +493,15 @@
     }
 
     /**
-     * Class to convert a GestureDescription to a series of MotionEvents.
+     * Class to convert a GestureDescription to a series of GestureSteps.
      *
      * @hide
      */
     public static class MotionEventGenerator {
-        /**
-         * Constants used to initialize all MotionEvents
-         */
-        private static final int EVENT_META_STATE = 0;
-        private static final int EVENT_BUTTON_STATE = 0;
-        private static final int EVENT_DEVICE_ID = 0;
-        private static final int EVENT_EDGE_FLAGS = 0;
-        private static final int EVENT_SOURCE = InputDevice.SOURCE_TOUCHSCREEN;
-        private static final int EVENT_FLAGS = 0;
-        private static final float EVENT_X_PRECISION = 1;
-        private static final float EVENT_Y_PRECISION = 1;
-
         /* Lazily-created scratch memory for processing touches */
         private static TouchPoint[] sCurrentTouchPoints;
-        private static TouchPoint[] sLastTouchPoints;
-        private static PointerCoords[] sPointerCoords;
-        private static PointerProperties[] sPointerProps;
 
-        static List<GestureStep> getGestureStepsFromGestureDescription(
+        public static List<GestureStep> getGestureStepsFromGestureDescription(
                 GestureDescription description, int sampleTimeMs) {
             final List<GestureStep> gestureSteps = new ArrayList<>();
 
@@ -474,31 +526,6 @@
             return gestureSteps;
         }
 
-        public static List<MotionEvent> getMotionEventsFromGestureSteps(List<GestureStep> steps) {
-            final List<MotionEvent> motionEvents = new ArrayList<>();
-
-            // Number of points in last touch event
-            int lastTouchPointSize = 0;
-            TouchPoint[] lastTouchPoints;
-
-            for (int i = 0; i < steps.size(); i++) {
-                GestureStep step = steps.get(i);
-                int currentTouchPointSize = step.numTouchPoints;
-                lastTouchPoints = getLastTouchPoints(
-                        Math.max(lastTouchPointSize, currentTouchPointSize));
-
-                appendMoveEventIfNeeded(motionEvents, lastTouchPoints, lastTouchPointSize,
-                        step.touchPoints, currentTouchPointSize, step.timeSinceGestureStart);
-                lastTouchPointSize = appendUpEvents(motionEvents, lastTouchPoints,
-                        lastTouchPointSize, step.touchPoints, currentTouchPointSize,
-                        step.timeSinceGestureStart);
-                lastTouchPointSize = appendDownEvents(motionEvents, lastTouchPoints,
-                        lastTouchPointSize, step.touchPoints, currentTouchPointSize,
-                        step.timeSinceGestureStart);
-            }
-            return motionEvents;
-        }
-
         private static TouchPoint[] getCurrentTouchPoints(int requiredCapacity) {
             if ((sCurrentTouchPoints == null) || (sCurrentTouchPoints.length < requiredCapacity)) {
                 sCurrentTouchPoints = new TouchPoint[requiredCapacity];
@@ -508,133 +535,5 @@
             }
             return sCurrentTouchPoints;
         }
-
-        private static TouchPoint[] getLastTouchPoints(int requiredCapacity) {
-            if ((sLastTouchPoints == null) || (sLastTouchPoints.length < requiredCapacity)) {
-                sLastTouchPoints = new TouchPoint[requiredCapacity];
-                for (int i = 0; i < requiredCapacity; i++) {
-                    sLastTouchPoints[i] = new TouchPoint();
-                }
-            }
-            return sLastTouchPoints;
-        }
-
-        private static PointerCoords[] getPointerCoords(int requiredCapacity) {
-            if ((sPointerCoords == null) || (sPointerCoords.length < requiredCapacity)) {
-                sPointerCoords = new PointerCoords[requiredCapacity];
-                for (int i = 0; i < requiredCapacity; i++) {
-                    sPointerCoords[i] = new PointerCoords();
-                }
-            }
-            return sPointerCoords;
-        }
-
-        private static PointerProperties[] getPointerProps(int requiredCapacity) {
-            if ((sPointerProps == null) || (sPointerProps.length < requiredCapacity)) {
-                sPointerProps = new PointerProperties[requiredCapacity];
-                for (int i = 0; i < requiredCapacity; i++) {
-                    sPointerProps[i] = new PointerProperties();
-                }
-            }
-            return sPointerProps;
-        }
-
-        private static void appendMoveEventIfNeeded(List<MotionEvent> motionEvents,
-                TouchPoint[] lastTouchPoints, int lastTouchPointsSize,
-                TouchPoint[] currentTouchPoints, int currentTouchPointsSize, long currentTime) {
-            /* Look for pointers that have moved */
-            boolean moveFound = false;
-            for (int i = 0; i < currentTouchPointsSize; i++) {
-                int lastPointsIndex = findPointByPathIndex(lastTouchPoints, lastTouchPointsSize,
-                        currentTouchPoints[i].mPathIndex);
-                if (lastPointsIndex >= 0) {
-                    moveFound |= (lastTouchPoints[lastPointsIndex].mX != currentTouchPoints[i].mX)
-                            || (lastTouchPoints[lastPointsIndex].mY != currentTouchPoints[i].mY);
-                    lastTouchPoints[lastPointsIndex].copyFrom(currentTouchPoints[i]);
-                }
-            }
-
-            if (moveFound) {
-                long downTime = motionEvents.get(motionEvents.size() - 1).getDownTime();
-                motionEvents.add(obtainMotionEvent(downTime, currentTime, MotionEvent.ACTION_MOVE,
-                        lastTouchPoints, lastTouchPointsSize));
-            }
-        }
-
-        private static int appendUpEvents(List<MotionEvent> motionEvents,
-                TouchPoint[] lastTouchPoints, int lastTouchPointsSize,
-                TouchPoint[] currentTouchPoints, int currentTouchPointsSize, long currentTime) {
-            /* Look for a pointer at the end of its path */
-            for (int i = 0; i < currentTouchPointsSize; i++) {
-                if (currentTouchPoints[i].mIsEndOfPath) {
-                    int indexOfUpEvent = findPointByPathIndex(lastTouchPoints, lastTouchPointsSize,
-                            currentTouchPoints[i].mPathIndex);
-                    if (indexOfUpEvent < 0) {
-                        continue; // Should not happen
-                    }
-                    long downTime = motionEvents.get(motionEvents.size() - 1).getDownTime();
-                    int action = (lastTouchPointsSize == 1) ? MotionEvent.ACTION_UP
-                            : MotionEvent.ACTION_POINTER_UP;
-                    action |= indexOfUpEvent << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
-                    motionEvents.add(obtainMotionEvent(downTime, currentTime, action,
-                            lastTouchPoints, lastTouchPointsSize));
-                    /* Remove this point from lastTouchPoints */
-                    for (int j = indexOfUpEvent; j < lastTouchPointsSize - 1; j++) {
-                        lastTouchPoints[j].copyFrom(lastTouchPoints[j+1]);
-                    }
-                    lastTouchPointsSize--;
-                }
-            }
-            return lastTouchPointsSize;
-        }
-
-        private static int appendDownEvents(List<MotionEvent> motionEvents,
-                TouchPoint[] lastTouchPoints, int lastTouchPointsSize,
-                TouchPoint[] currentTouchPoints, int currentTouchPointsSize, long currentTime) {
-            /* Look for a pointer that is just starting */
-            for (int i = 0; i < currentTouchPointsSize; i++) {
-                if (currentTouchPoints[i].mIsStartOfPath) {
-                    /* Add the point to last coords and use the new array to generate the event */
-                    lastTouchPoints[lastTouchPointsSize++].copyFrom(currentTouchPoints[i]);
-                    int action = (lastTouchPointsSize == 1) ? MotionEvent.ACTION_DOWN
-                            : MotionEvent.ACTION_POINTER_DOWN;
-                    long downTime = (action == MotionEvent.ACTION_DOWN) ? currentTime :
-                            motionEvents.get(motionEvents.size() - 1).getDownTime();
-                    action |= i << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
-                    motionEvents.add(obtainMotionEvent(downTime, currentTime, action,
-                            lastTouchPoints, lastTouchPointsSize));
-                }
-            }
-            return lastTouchPointsSize;
-        }
-
-        private static MotionEvent obtainMotionEvent(long downTime, long eventTime, int action,
-                TouchPoint[] touchPoints, int touchPointsSize) {
-            PointerCoords[] pointerCoords = getPointerCoords(touchPointsSize);
-            PointerProperties[] pointerProperties = getPointerProps(touchPointsSize);
-            for (int i = 0; i < touchPointsSize; i++) {
-                pointerProperties[i].id = touchPoints[i].mPathIndex;
-                pointerProperties[i].toolType = MotionEvent.TOOL_TYPE_UNKNOWN;
-                pointerCoords[i].clear();
-                pointerCoords[i].pressure = 1.0f;
-                pointerCoords[i].size = 1.0f;
-                pointerCoords[i].x = touchPoints[i].mX;
-                pointerCoords[i].y = touchPoints[i].mY;
-            }
-            return MotionEvent.obtain(downTime, eventTime, action, touchPointsSize,
-                    pointerProperties, pointerCoords, EVENT_META_STATE, EVENT_BUTTON_STATE,
-                    EVENT_X_PRECISION, EVENT_Y_PRECISION, EVENT_DEVICE_ID, EVENT_EDGE_FLAGS,
-                    EVENT_SOURCE, EVENT_FLAGS);
-        }
-
-        private static int findPointByPathIndex(TouchPoint[] touchPoints, int touchPointsSize,
-                int pathIndex) {
-            for (int i = 0; i < touchPointsSize; i++) {
-                if (touchPoints[i].mPathIndex == pathIndex) {
-                    return i;
-                }
-            }
-            return -1;
-        }
     }
 }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 65f74d1..312d3a5 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -561,8 +561,11 @@
         /** ID of stack that always on top (always visible) when it exist. */
         public static final int PINNED_STACK_ID = DOCKED_STACK_ID + 1;
 
+        /** Recents activity stack ID. */
+        public static final int RECENTS_STACK_ID = PINNED_STACK_ID + 1;
+
         /** Last static stack stack ID. */
-        public static final int LAST_STATIC_STACK_ID = PINNED_STACK_ID;
+        public static final int LAST_STATIC_STACK_ID = RECENTS_STACK_ID;
 
         /** Start of ID range used by stacks that are created dynamically. */
         public static final int FIRST_DYNAMIC_STACK_ID = LAST_STATIC_STACK_ID + 1;
@@ -735,6 +738,13 @@
         }
 
         /**
+         * Returns true if the input {@param stackId} is HOME_STACK_ID or RECENTS_STACK_ID
+         */
+        public static boolean isHomeOrRecentsStack(int stackId) {
+            return stackId == HOME_STACK_ID || stackId == RECENTS_STACK_ID;
+        }
+
+        /**
          * Returns true if activities contained in this stack can request visible behind by
          * calling {@link Activity#requestVisibleBehind}.
          */
@@ -760,7 +770,8 @@
 
         /** Returns true if the input stack and its content can affect the device orientation. */
         public static boolean canSpecifyOrientation(int stackId) {
-            return stackId == HOME_STACK_ID || stackId == FULLSCREEN_WORKSPACE_STACK_ID;
+            return stackId == HOME_STACK_ID || stackId == RECENTS_STACK_ID
+                    || stackId == FULLSCREEN_WORKSPACE_STACK_ID;
         }
     }
 
@@ -1509,7 +1520,7 @@
      * Ignores all tasks that are on the home stack.
      * @hide
      */
-    public static final int RECENT_IGNORE_HOME_STACK_TASKS = 0x0008;
+    public static final int RECENT_IGNORE_HOME_AND_RECENTS_STACK_TASKS = 0x0008;
 
     /**
      * Ignores the top task in the docked stack.
@@ -2052,15 +2063,6 @@
         }
     }
 
-    /** @hide */
-    public boolean isInHomeStack(int taskId) {
-        try {
-            return getService().isInHomeStack(taskId);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
     /**
      * Flag for {@link #moveTaskToFront(int, int)}: also move the "home"
      * activity along with the task, so it is positioned immediately behind
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index bfa6d34..913edfd8 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -62,6 +62,13 @@
     public static final int APP_TRANSITION_TIMEOUT = 3;
 
     /**
+     * Grant Uri permissions from one app to another. This method only extends
+     * permission grants if {@code callingUid} has permission to them.
+     */
+    public abstract void grantUriPermissionFromIntent(int callingUid, String targetPkg,
+            Intent intent, int targetUserId);
+
+    /**
      * Verify that calling app has access to the given provider.
      */
     public abstract String checkContentProviderAccess(String authority, int userId);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index ba6bc15..67fbc5a 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -241,8 +241,10 @@
     public static final int OP_RUN_IN_BACKGROUND = 63;
     /** @hide */
     public static final int OP_AUDIO_ACCESSIBILITY_VOLUME = 64;
+    /** @hide Read the phone number. */
+    public static final int OP_READ_PHONE_NUMBER = 65;
     /** @hide */
-    public static final int _NUM_OP = 65;
+    public static final int _NUM_OP = 66;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -343,6 +345,8 @@
     /** @hide Get device accounts. */
     public static final String OPSTR_GET_ACCOUNTS
             = "android:get_accounts";
+    public static final String OPSTR_READ_PHONE_NUMBER
+            = "android:read_phone_number";
 
     private static final int[] RUNTIME_PERMISSIONS_OPS = {
             // Contacts
@@ -367,6 +371,7 @@
             OP_FINE_LOCATION,
             // Phone
             OP_READ_PHONE_STATE,
+            OP_READ_PHONE_NUMBER,
             OP_CALL_PHONE,
             OP_READ_CALL_LOG,
             OP_WRITE_CALL_LOG,
@@ -455,6 +460,7 @@
             OP_GET_ACCOUNTS,
             OP_RUN_IN_BACKGROUND,
             OP_AUDIO_ACCESSIBILITY_VOLUME,
+            OP_READ_PHONE_NUMBER,
     };
 
     /**
@@ -527,6 +533,7 @@
             OPSTR_GET_ACCOUNTS,
             null,
             null, // OP_AUDIO_ACCESSIBILITY_VOLUME
+            OPSTR_READ_PHONE_NUMBER,
     };
 
     /**
@@ -599,6 +606,7 @@
             "GET_ACCOUNTS",
             "RUN_IN_BACKGROUND",
             "AUDIO_ACCESSIBILITY_VOLUME",
+            "READ_PHONE_NUMBER",
     };
 
     /**
@@ -671,6 +679,7 @@
             Manifest.permission.GET_ACCOUNTS,
             null, // no permission for running in background
             null, // no permission for changing accessibility volume
+            Manifest.permission.READ_PHONE_NUMBER,
     };
 
     /**
@@ -744,6 +753,7 @@
             null, // GET_ACCOUNTS
             null, // RUN_IN_BACKGROUND
             UserManager.DISALLOW_ADJUST_VOLUME, //AUDIO_ACCESSIBILITY_VOLUME
+            null, // READ_PHONE_NUMBER
     };
 
     /**
@@ -816,6 +826,7 @@
             false, // GET_ACCOUNTS
             false, // RUN_IN_BACKGROUND
             false, // AUDIO_ACCESSIBILITY_VOLUME
+            false, // READ_PHONE_NUMBER
     };
 
     /**
@@ -887,6 +898,7 @@
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_ALLOWED,  // OP_RUN_IN_BACKGROUND
             AppOpsManager.MODE_ALLOWED,  // OP_AUDIO_ACCESSIBILITY_VOLUME
+            AppOpsManager.MODE_ALLOWED,
     };
 
     /**
@@ -962,6 +974,7 @@
             false,
             false,
             false, // OP_AUDIO_ACCESSIBILITY_VOLUME
+            false,
     };
 
     /**
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index b199984..627e661 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -58,9 +58,11 @@
 import android.content.res.XmlResourceParser;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -81,6 +83,7 @@
 import dalvik.system.VMRuntime;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.UserIcons;
@@ -1175,21 +1178,21 @@
     }
 
     @Override
-    public Drawable getManagedUserBadgedDrawable(Drawable drawable, Rect badgeLocation,
-            int badgeDensity) {
-        Drawable badgeDrawable = getDrawableForDensity(
-            com.android.internal.R.drawable.ic_corp_badge, badgeDensity);
-        return getBadgedDrawable(drawable, badgeDrawable, badgeLocation, true);
-    }
-
-    @Override
     public Drawable getUserBadgedIcon(Drawable icon, UserHandle user) {
-        final int badgeResId = getBadgeResIdForUser(user.getIdentifier());
-        if (badgeResId == 0) {
+        if (!isManagedProfile(user.getIdentifier())) {
             return icon;
         }
-        Drawable badgeIcon = getDrawable("system", badgeResId, null);
-        return getBadgedDrawable(icon, badgeIcon, null, true);
+        Drawable badgeShadow = getDrawable("system",
+                com.android.internal.R.drawable.ic_corp_icon_badge_shadow, null);
+        Drawable badgeColor = getDrawable("system",
+                com.android.internal.R.drawable.ic_corp_icon_badge_color, null);
+        badgeColor.setTint(getUserBadgeColor(user));
+        Drawable badgeForeground = getDrawable("system",
+                com.android.internal.R.drawable.ic_corp_icon_badge_case, null);
+
+        Drawable badge = new LayerDrawable(
+                new Drawable[] {badgeShadow, badgeColor, badgeForeground });
+        return getBadgedDrawable(icon, badge, null, true);
     }
 
     @Override
@@ -1202,16 +1205,53 @@
         return getBadgedDrawable(drawable, badgeDrawable, badgeLocation, true);
     }
 
+    // Should have enough colors to cope with UserManagerService.getMaxManagedProfiles()
+    @VisibleForTesting
+    public static final int[] CORP_BADGE_COLORS = new int[] {
+        com.android.internal.R.color.profile_badge_1,
+        com.android.internal.R.color.profile_badge_2,
+        com.android.internal.R.color.profile_badge_3
+    };
+
+    @VisibleForTesting
+    public static final int[] CORP_BADGE_LABEL_RES_ID = new int[] {
+        com.android.internal.R.string.managed_profile_label_badge,
+        com.android.internal.R.string.managed_profile_label_badge_2,
+        com.android.internal.R.string.managed_profile_label_badge_3
+    };
+
+    private int getUserBadgeColor(UserHandle user) {
+        int badge = getUserManager().getManagedProfileBadge(user.getIdentifier());
+        if (badge < 0) {
+            badge = 0;
+        }
+        int resourceId = CORP_BADGE_COLORS[badge % CORP_BADGE_COLORS.length];
+        return Resources.getSystem().getColor(resourceId, null);
+    }
+
     @Override
     public Drawable getUserBadgeForDensity(UserHandle user, int density) {
-        return getManagedProfileIconForDensity(user, com.android.internal.R.drawable.ic_corp_badge,
-                density);
+        Drawable badgeColor = getManagedProfileIconForDensity(user,
+                com.android.internal.R.drawable.ic_corp_badge_color, density);
+        if (badgeColor == null) {
+            return null;
+        }
+        badgeColor.setTint(getUserBadgeColor(user));
+        Drawable badgeForeground = getDrawableForDensity(
+                com.android.internal.R.drawable.ic_corp_badge_case, density);
+        Drawable badge = new LayerDrawable(
+                new Drawable[] {badgeColor, badgeForeground });
+        return badge;
     }
 
     @Override
     public Drawable getUserBadgeForDensityNoBackground(UserHandle user, int density) {
-        return getManagedProfileIconForDensity(user,
+        Drawable badge = getManagedProfileIconForDensity(user,
                 com.android.internal.R.drawable.ic_corp_badge_no_background, density);
+        if (badge != null) {
+            badge.setTint(getUserBadgeColor(user));
+        }
+        return badge;
     }
 
     private Drawable getDrawableForDensity(int drawableId, int density) {
@@ -1231,8 +1271,9 @@
     @Override
     public CharSequence getUserBadgedLabel(CharSequence label, UserHandle user) {
         if (isManagedProfile(user.getIdentifier())) {
-            return Resources.getSystem().getString(
-                    com.android.internal.R.string.managed_profile_label_badge, label);
+            int badge = getUserManager().getManagedProfileBadge(user.getIdentifier());
+            int resourceId = CORP_BADGE_LABEL_RES_ID[badge % CORP_BADGE_LABEL_RES_ID.length];
+            return Resources.getSystem().getString(resourceId, label);
         }
         return label;
     }
@@ -2355,14 +2396,6 @@
         return drawable;
     }
 
-    private int getBadgeResIdForUser(int userId) {
-        // Return the framework-provided badge.
-        if (isManagedProfile(userId)) {
-            return com.android.internal.R.drawable.ic_corp_icon_badge;
-        }
-        return 0;
-    }
-
     private boolean isManagedProfile(int userId) {
         return getUserManager().isManagedProfile(userId);
     }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index b8540f8..5f706dc 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2064,9 +2064,20 @@
                 ? packageInfo.getCompatibilityInfo()
                 : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
 
-        context.mResources = createResources(activityToken, packageInfo, displayId,
-                overrideConfiguration, compatInfo);
-        context.mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(displayId,
+        final ResourcesManager resourcesManager = ResourcesManager.getInstance();
+
+        // Create the base resources for which all configuration contexts for this Activity
+        // will be rebased upon.
+        context.mResources = resourcesManager.createBaseActivityResources(activityToken,
+                packageInfo.getResDir(),
+                packageInfo.getSplitResDirs(),
+                packageInfo.getOverlayDirs(),
+                packageInfo.getApplicationInfo().sharedLibraryFiles,
+                displayId,
+                overrideConfiguration,
+                compatInfo,
+                packageInfo.getClassLoader());
+        context.mDisplay = resourcesManager.getAdjustedDisplay(displayId,
                 context.mResources.getDisplayAdjustments());
         return context;
     }
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 6e2c464..f29e576 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -200,6 +200,7 @@
             @Nullable Message cancelCallback) {
         this(context);
         mCancelable = cancelable;
+        updateWindowForCancelable();
         mCancelMessage = cancelCallback;
     }
 
@@ -207,6 +208,7 @@
             @Nullable OnCancelListener cancelListener) {
         this(context);
         mCancelable = cancelable;
+        updateWindowForCancelable();
         setOnCancelListener(cancelListener);
     }
 
@@ -1187,6 +1189,7 @@
      */
     public void setCancelable(boolean flag) {
         mCancelable = flag;
+        updateWindowForCancelable();
     }
 
     /**
@@ -1200,6 +1203,7 @@
     public void setCanceledOnTouchOutside(boolean cancel) {
         if (cancel && !mCancelable) {
             mCancelable = true;
+            updateWindowForCancelable();
         }
         
         mWindow.setCloseOnTouchOutside(cancel);
@@ -1351,4 +1355,8 @@
             }
         }
     }
+
+    private void updateWindowForCancelable() {
+        mWindow.setCloseOnSwipeEnabled(mCancelable);
+    }
 }
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index 7e0486f..10d584f 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -90,7 +90,7 @@
                                     decorView.getViewTreeObserver().removeOnPreDrawListener(this);
                                 }
                             }
-                            return mIsReadyForTransition;
+                            return false;
                         }
                     });
         }
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 9ea3f83..92ba440 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1175,15 +1175,17 @@
                                 f.mView.setSaveFromParentEnabled(false);
                                 if (container != null) {
                                     container.addView(f.mView);
-                                    f.mIsNewlyAdded = true;
                                 }
                                 if (f.mHidden) {
                                     f.mView.setVisibility(View.GONE);
-                                    f.mIsNewlyAdded = false; // No animation required
                                 }
                                 f.onViewCreated(f.mView, f.mSavedFragmentState);
                                 dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState,
                                         false);
+                                // Only animate the view if it is visible. This is done after
+                                // dispatchOnFragmentViewCreated in case visibility is changed
+                                f.mIsNewlyAdded = (f.mView.getVisibility() == View.VISIBLE)
+                                        && f.mContainer != null;
                             }
                         }
 
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 1a36d1a..640ca6c 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -370,7 +370,6 @@
     // Start of L transactions
     String getTagForIntentSender(in IIntentSender sender, in String prefix);
     boolean startUserInBackground(int userid);
-    boolean isInHomeStack(int taskId);
     void startLockTaskModeById(int taskId);
     void startLockTaskModeByToken(in IBinder token);
     void stopLockTaskMode();
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 2a7341a..927ef6c 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -2,21 +2,22 @@
 **
 ** Copyright 2007, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
 package android.app;
 
+import android.app.IOnNotificationChannelCreatedListener;
 import android.app.ITransientNotification;
 import android.app.Notification;
 import android.app.NotificationChannel;
@@ -58,7 +59,8 @@
     int getImportance(String pkg, int uid);
     int getPackageImportance(String pkg);
 
-    void createNotificationChannel(String pkg, in NotificationChannel channel);
+    void createNotificationChannel(String pkg, in NotificationChannel channel,
+            in IOnNotificationChannelCreatedListener listener);
     void updateNotificationChannelForPackage(String pkg, int uid, in NotificationChannel channel);
     NotificationChannel getNotificationChannel(String pkg, String channelId);
     NotificationChannel getNotificationChannelForPackage(String pkg, int uid, String channelId);
diff --git a/core/java/android/app/IOnNotificationChannelCreatedListener.aidl b/core/java/android/app/IOnNotificationChannelCreatedListener.aidl
new file mode 100644
index 0000000..8e66542
--- /dev/null
+++ b/core/java/android/app/IOnNotificationChannelCreatedListener.aidl
@@ -0,0 +1,25 @@
+/*
+**
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.app;
+
+import android.app.NotificationChannel;
+
+/** {@hide} */
+oneway interface IOnNotificationChannelCreatedListener {
+    void onNotificationChannelCreated(in NotificationChannel channel);
+}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 1fd082f4..c1e2072 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -37,6 +37,7 @@
 import android.graphics.drawable.Icon;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
+import android.media.PlayerBase;
 import android.media.session.MediaSession;
 import android.net.Uri;
 import android.os.BadParcelableException;
@@ -2821,6 +2822,7 @@
          */
         @Deprecated
         public Builder setSound(Uri sound, int streamType) {
+            PlayerBase.deprecateStreamTypeForPlayback(streamType, "Notification", "setSound()");
             mN.sound = sound;
             mN.audioStreamType = streamType;
             return this;
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index bfabc0d..79a01c2 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -28,6 +28,7 @@
 import android.text.TextUtils;
 
 import java.io.IOException;
+import java.util.Arrays;
 
 /**
  * A representation of settings that apply to a collection of similarly themed notifications.
@@ -48,10 +49,12 @@
     private static final String ATT_IMPORTANCE = "importance";
     private static final String ATT_LIGHTS = "lights";
     private static final String ATT_VIBRATION = "vibration";
+    private static final String ATT_VIBRATION_ENABLED = "vibration_enabled";
     private static final String ATT_SOUND = "sound";
     //TODO: add audio attributes support
     private static final String ATT_AUDIO_ATTRIBUTES = "audio_attributes";
     private static final String ATT_USER_LOCKED = "locked";
+    private static final String DELIMITER = ",";
 
     /**
      * @hide
@@ -96,8 +99,9 @@
     private int mLockscreenVisibility = DEFAULT_VISIBILITY;
     private Uri mSound;
     private boolean mLights;
-    private boolean mVibration;
+    private long[] mVibration;
     private int mUserLockedFields;
+    private boolean mVibrationEnabled;
 
     /**
      * Creates a notification channel.
@@ -130,8 +134,9 @@
             mSound = null;
         }
         mLights = in.readByte() != 0;
-        mVibration = in.readByte() != 0;
+        mVibration = in.createLongArray();
         mUserLockedFields = in.readInt();
+        mVibrationEnabled = in.readByte() != 0;
     }
 
     @Override
@@ -153,8 +158,9 @@
             dest.writeByte((byte) 0);
         }
         dest.writeByte(mLights ? (byte) 1 : (byte) 0);
-        dest.writeByte(mVibration ? (byte) 1 : (byte) 0);
+        dest.writeLongArray(mVibration);
         dest.writeInt(mUserLockedFields);
+        dest.writeByte(mVibrationEnabled ? (byte) 1 : (byte) 0);
     }
 
     /**
@@ -221,12 +227,20 @@
     }
 
     /**
-     * Sets whether notification posted to this channel should vibrate, even if individual
-     * notifications are marked as having vibration only modifiable before the channel is submitted
-     * to the NotificationManager.
+     * Sets whether notification posted to this channel should vibrate. The vibration pattern can
+     * be set with {@link #setVibrationPattern(long[])}. Only modifiable before the channel is
+     * submitted to the NotificationManager.
      */
-    public void setVibration(boolean vibration) {
-        this.mVibration = vibration;
+    public void enableVibration(boolean vibration) {
+        this.mVibrationEnabled = vibration;
+    }
+
+    /**
+     * Sets whether notification posted to this channel should vibrate. Only modifiable before the
+     * channel is submitted to the NotificationManager.
+     */
+    public void setVibrationPattern(long[] vibrationPattern) {
+        this.mVibration = vibrationPattern;
     }
 
     /**
@@ -277,6 +291,14 @@
      * Returns whether notifications posted to this channel always vibrate.
      */
     public boolean shouldVibrate() {
+        return mVibrationEnabled;
+    }
+
+    /**
+     * Returns the vibration pattern for notifications posted to this channel. Will be ignored if
+     * vibration is not enabled ({@link #shouldVibrate()}.
+     */
+    public long[] getVibrationPattern() {
         return mVibration;
     }
 
@@ -307,7 +329,8 @@
         setLockscreenVisibility(safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY));
         setSound(safeUri(parser, ATT_SOUND));
         setLights(safeBool(parser, ATT_LIGHTS, false));
-        setVibration(safeBool(parser, ATT_VIBRATION, false));
+        enableVibration(safeBool(parser, ATT_VIBRATION_ENABLED, false));
+        setVibrationPattern(safeLongArray(parser, ATT_VIBRATION, null));
         lockFields(safeInt(parser, ATT_USER_LOCKED, 0));
     }
 
@@ -338,7 +361,10 @@
             out.attribute(null, ATT_LIGHTS, Boolean.toString(shouldShowLights()));
         }
         if (shouldVibrate()) {
-            out.attribute(null, ATT_VIBRATION, Boolean.toString(shouldVibrate()));
+            out.attribute(null, ATT_VIBRATION_ENABLED, Boolean.toString(shouldVibrate()));
+        }
+        if (getVibrationPattern() != null) {
+            out.attribute(null, ATT_VIBRATION, longArrayToString(getVibrationPattern()));
         }
         if (getUserLockedFields() != 0) {
             out.attribute(null, ATT_USER_LOCKED, Integer.toString(getUserLockedFields()));
@@ -369,8 +395,9 @@
             record.put(ATT_SOUND, getSound().toString());
         }
         record.put(ATT_LIGHTS, Boolean.toString(shouldShowLights()));
-        record.put(ATT_VIBRATION, Boolean.toString(shouldVibrate()));
+        record.put(ATT_VIBRATION_ENABLED, Boolean.toString(shouldVibrate()));
         record.put(ATT_USER_LOCKED, Integer.toString(getUserLockedFields()));
+        record.put(ATT_VIBRATION, longArrayToString(getVibrationPattern()));
 
         return record;
     }
@@ -400,6 +427,30 @@
         return Boolean.parseBoolean(value);
     }
 
+    private static long[] safeLongArray(XmlPullParser parser, String att, long[] defValue) {
+        final String attributeValue = parser.getAttributeValue(null, att);
+        if (TextUtils.isEmpty(attributeValue)) return defValue;
+        String[] values = attributeValue.split(DELIMITER);
+        long[] longValues = new long[values.length];
+        for (int i = 0; i < values.length; i++) {
+            try {
+                longValues[i] = Long.parseLong(values[i]);
+            } catch (NumberFormatException e) {
+                longValues[i] = 0;
+            }
+        }
+        return longValues;
+    }
+
+    private static String longArrayToString(long[] values) {
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < values.length - 1; i++) {
+            sb.append(values[i]).append(DELIMITER);
+        }
+        sb.append(values[values.length - 1]);
+        return sb.toString();
+    }
+
     public static final Creator<NotificationChannel> CREATOR = new Creator<NotificationChannel>() {
         @Override
         public NotificationChannel createFromParcel(Parcel in) {
@@ -424,34 +475,35 @@
 
         NotificationChannel that = (NotificationChannel) o;
 
-        if (getImportance() != that.getImportance()) return false;
+        if (mImportance != that.mImportance) return false;
         if (mBypassDnd != that.mBypassDnd) return false;
-        if (getLockscreenVisibility() != that.getLockscreenVisibility()) return false;
+        if (mLockscreenVisibility != that.mLockscreenVisibility) return false;
         if (mLights != that.mLights) return false;
-        if (mVibration != that.mVibration) return false;
-        if (getUserLockedFields() != that.getUserLockedFields()) return false;
-        if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false;
-        if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null)
-            return false;
-        return getSound() != null ? getSound().equals(
-                that.getSound()) : that.getSound() == null;
+        if (mUserLockedFields != that.mUserLockedFields) return false;
+        if (mVibrationEnabled != that.mVibrationEnabled) return false;
+        if (mId != null ? !mId.equals(that.mId) : that.mId != null) return false;
+        if (mName != null ? !mName.equals(that.mName) : that.mName != null) return false;
+        if (mSound != null ? !mSound.equals(that.mSound) : that.mSound != null) return false;
+        return Arrays.equals(mVibration, that.mVibration);
 
     }
 
     @Override
     public int hashCode() {
-        int result = getId() != null ? getId().hashCode() : 0;
-        result = 31 * result + (getName() != null ? getName().hashCode() : 0);
-        result = 31 * result + getImportance();
+        int result = mId != null ? mId.hashCode() : 0;
+        result = 31 * result + (mName != null ? mName.hashCode() : 0);
+        result = 31 * result + mImportance;
         result = 31 * result + (mBypassDnd ? 1 : 0);
-        result = 31 * result + getLockscreenVisibility();
-        result = 31 * result + (getSound() != null ? getSound().hashCode() : 0);
+        result = 31 * result + mLockscreenVisibility;
+        result = 31 * result + (mSound != null ? mSound.hashCode() : 0);
         result = 31 * result + (mLights ? 1 : 0);
-        result = 31 * result + (mVibration ? 1 : 0);
-        result = 31 * result + getUserLockedFields();
+        result = 31 * result + Arrays.hashCode(mVibration);
+        result = 31 * result + mUserLockedFields;
+        result = 31 * result + (mVibrationEnabled ? 1 : 0);
         return result;
     }
 
+
     @Override
     public String toString() {
         return "NotificationChannel{" +
@@ -462,8 +514,9 @@
                 ", mLockscreenVisibility=" + mLockscreenVisibility +
                 ", mSound=" + mSound +
                 ", mLights=" + mLights +
-                ", mVibration=" + mVibration +
+                ", mVibration=" + Arrays.toString(mVibration) +
                 ", mUserLockedFields=" + mUserLockedFields +
+                ", mVibrationEnabled=" + mVibrationEnabled +
                 '}';
     }
 }
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 047f349..7693d76 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.TestApi;
 import android.app.Notification.Builder;
@@ -30,6 +31,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.RemoteException;
@@ -379,12 +381,42 @@
     }
 
     /**
-     * Creates a notification channel that notifications can be posted to.
+     * Listener passed to {@link NotificationManager#createNotificationChannel} to notify
+     * caller of result.
      */
-    public void createNotificationChannel(NotificationChannel channel) {
+    public interface OnNotificationChannelCreatedListener {
+        /**
+         * @param createdChannel NotificationChannel created by the system.  Value is null iff an
+         *   exception was thrown during channel creation.
+         */
+        public void onNotificationChannelCreated(NotificationChannel createdChannel);
+    }
+
+    /**
+     * Creates a notification channel that notifications can be posted to.
+     *
+     * @param channel  the channel to attempt to create.  Note that the created channel may differ
+     *                 from this value.
+     * @param listener Called when operation is finished.
+     * @param handler  The handler to invoke the listener on, or {@code null} to use the main
+     *                 handler.
+     */
+    public void createNotificationChannel(
+            @NonNull NotificationChannel channel,
+            @NonNull OnNotificationChannelCreatedListener listener,
+            @Nullable Handler handler) {
         INotificationManager service = getService();
         try {
-            service.createNotificationChannel(mContext.getPackageName(), channel);
+            final Handler actualHandler =
+                    handler != null ? handler : new Handler(Looper.getMainLooper());
+            service.createNotificationChannel(mContext.getPackageName(), channel,
+                    new IOnNotificationChannelCreatedListener.Stub() {
+                        @Override public void onNotificationChannelCreated(
+                                NotificationChannel channel) {
+                            actualHandler.post(
+                                    () -> { listener.onNotificationChannelCreated(channel); });
+                        }
+                    });
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -583,7 +615,7 @@
      * <p>
      * Callers can only update rules that they own. See {@link AutomaticZenRule#getOwner}.
      * @param id The id of the rule to update
-     * @param automaticZenRule the rule to update. 
+     * @param automaticZenRule the rule to update.
      * @return Whether the rule was successfully updated.
      */
     public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule) {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 3ecc309..67ce342 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -514,7 +514,7 @@
                 new CachedServiceFetcher<WifiAwareManager>() {
             @Override
             public WifiAwareManager createService(ContextImpl ctx) throws ServiceNotFoundException {
-                IBinder b = ServiceManager.getService(Context.WIFI_AWARE_SERVICE);
+                IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_AWARE_SERVICE);
                 IWifiAwareManager service = IWifiAwareManager.Stub.asInterface(b);
                 if (service == null) {
                     return null;
@@ -831,7 +831,7 @@
                         service = createService(ctx);
                         cache[mCacheIndex] = service;
                     } catch (ServiceNotFoundException e) {
-                        Log.wtf(TAG, e.getMessage(), e);
+                        onServiceNotFound(e);
                     }
                 }
                 return (T)service;
@@ -849,13 +849,13 @@
         private T mCachedInstance;
 
         @Override
-        public final T getService(ContextImpl unused) {
+        public final T getService(ContextImpl ctx) {
             synchronized (StaticServiceFetcher.this) {
                 if (mCachedInstance == null) {
                     try {
                         mCachedInstance = createService();
                     } catch (ServiceNotFoundException e) {
-                        Log.wtf(TAG, e.getMessage(), e);
+                        onServiceNotFound(e);
                     }
                 }
                 return mCachedInstance;
@@ -888,7 +888,7 @@
                     try {
                         mCachedInstance = createService(appContext != null ? appContext : ctx);
                     } catch (ServiceNotFoundException e) {
-                        Log.wtf(TAG, e.getMessage(), e);
+                        onServiceNotFound(e);
                     }
                 }
                 return mCachedInstance;
@@ -897,4 +897,15 @@
 
         public abstract T createService(Context applicationContext) throws ServiceNotFoundException;
     }
+
+    public static void onServiceNotFound(ServiceNotFoundException e) {
+        // We're mostly interested in tracking down long-lived core system
+        // components that might stumble if they obtain bad references; just
+        // emit a tidy log message for normal apps
+        if (android.os.Process.myUid() < android.os.Process.FIRST_APPLICATION_UID) {
+            Log.wtf(TAG, e.getMessage(), e);
+        } else {
+            Log.w(TAG, e.getMessage());
+        }
+    }
 }
diff --git a/core/java/android/app/admin/ConnectEvent.java b/core/java/android/app/admin/ConnectEvent.java
index c1646bb..b6b14f2 100644
--- a/core/java/android/app/admin/ConnectEvent.java
+++ b/core/java/android/app/admin/ConnectEvent.java
@@ -31,6 +31,7 @@
     /** The destination port number. */
     private final int port;
 
+    /** @hide */
     public ConnectEvent(String ipAddress, int port, String packageName, long timestamp) {
         super(packageName, timestamp);
         this.ipAddress = ipAddress;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 866a551..5600da6 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -151,6 +151,7 @@
      * <li>{@link #EXTRA_PROVISIONING_LOGO_URI}, optional</li>
      * <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>
      * </ul>
      *
      * <p>When managed provisioning has completed, broadcasts are sent to the application specified
@@ -513,6 +514,19 @@
         = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";
 
     /**
+     * Boolean extra that is used in conjunction with
+     * {@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE}. If it's set to {@code true}, the account will
+     * not be removed from the primary user after it is migrated to the newly created user or
+     * profile.
+     *
+     * <p> Defaults to {@code false}
+     *
+     * <p> Use with {@link #ACTION_PROVISION_MANAGED_PROFILE}.
+     */
+    public static final String EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION
+            = "android.app.extra.PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION";
+
+    /**
      * A String extra that, holds the email address of the account which a managed profile is
      * created for. Used with {@link #ACTION_PROVISION_MANAGED_PROFILE} and
      * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE}.
@@ -739,8 +753,13 @@
      * <p>The broadcast is limited to the primary profile, to the app specified in the provisioning
      * intent with action {@link #ACTION_PROVISION_MANAGED_PROFILE}.
      *
-     * <p>This intent will contain the extra {@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE} which
-     * corresponds to the account requested to be migrated at provisioning time, if any.
+     * <p>This intent will contain the following extras
+     * <ul>
+     * <li>{@link Intent#EXTRA_USER}, corresponds to the {@link UserHandle} of the managed
+     * profile.</li>
+     * <li>{@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE}, corresponds to the account requested to
+     * be migrated at provisioning time, if any.</li>
+     * </ul>
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_MANAGED_PROFILE_PROVISIONED
@@ -3844,14 +3863,22 @@
     }
 
     /**
-     * @return true if the device is managed by any device owner.
+     * Called by the system to find out whether the device is managed by a Device Owner.
      *
-     * <p>Requires the MANAGE_USERS permission.
+     * @return whether the device is managed by a Device Owner.
+     * @throws SecurityException if the caller is not the device owner, does not hold the
+     *         MANAGE_USERS permission and is not the system.
      *
      * @hide
      */
+    @SystemApi
+    @TestApi
     public boolean isDeviceManaged() {
-        return getDeviceOwnerComponentOnAnyUser() != null;
+        try {
+            return mService.hasDeviceOwner();
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -6411,7 +6438,7 @@
     }
 
     /**
-     * Called by a profile owner of a managed profile to set the name of the organization under
+     * Called by the device owner or profile owner to set the name of the organization under
      * management.
      * <p>
      * If the organization name needs to be localized, it is the responsibility of the
@@ -6420,7 +6447,7 @@
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param title The organization name or {@code null} to clear a previously set name.
-     * @throws SecurityException if {@code admin} is not a profile owner.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public void setOrganizationName(@NonNull ComponentName admin, @Nullable CharSequence title) {
         throwIfParentInstance("setOrganizationName");
@@ -6449,6 +6476,25 @@
     }
 
     /**
+     * Called by the system to retrieve the name of the organization managing the device.
+     *
+     * @return The organization name or {@code null} if none is set.
+     * @throws SecurityException if the caller is not the device owner, does not hold the
+     *         MANAGE_USERS permission and is not the system.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public @Nullable CharSequence getDeviceOwnerOrganizationName() {
+        try {
+            return mService.getDeviceOwnerOrganizationName();
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Retrieve the default title message used in the confirm credentials screen for a given user.
      *
      * @param userHandle The user id of the user we're interested in.
diff --git a/core/java/android/app/admin/DnsEvent.java b/core/java/android/app/admin/DnsEvent.java
index 63ea8db..30e107c 100644
--- a/core/java/android/app/admin/DnsEvent.java
+++ b/core/java/android/app/admin/DnsEvent.java
@@ -37,6 +37,7 @@
      */
     private final int ipAddressesCount;
 
+    /** @hide */
     public DnsEvent(String hostname, String[] ipAddresses, int ipAddressesCount,
             String packageName, long timestamp) {
         super(packageName, timestamp);
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 3bc8cd0..f303bbc 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -132,6 +132,7 @@
 
     boolean setDeviceOwner(in ComponentName who, String ownerName, int userId);
     ComponentName getDeviceOwnerComponent(boolean callingUserOnly);
+    boolean hasDeviceOwner();
     String getDeviceOwnerName();
     void clearDeviceOwner(String packageName);
     int getDeviceOwnerUserId();
@@ -293,6 +294,7 @@
 
     void setOrganizationName(in ComponentName admin, in CharSequence title);
     CharSequence getOrganizationName(in ComponentName admin);
+    CharSequence getDeviceOwnerOrganizationName();
     CharSequence getOrganizationNameForUser(int userHandle);
 
     int getUserProvisioningState();
diff --git a/core/java/android/app/admin/NetworkEvent.java b/core/java/android/app/admin/NetworkEvent.java
index 1dbff20..0de2665 100644
--- a/core/java/android/app/admin/NetworkEvent.java
+++ b/core/java/android/app/admin/NetworkEvent.java
@@ -16,6 +16,7 @@
 
 package android.app.admin;
 
+import android.content.pm.PackageManager;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.ParcelFormatException;
@@ -35,21 +36,29 @@
     /** The timestamp of the event being reported in milliseconds. */
     long timestamp;
 
-    protected NetworkEvent() {
+    /** @hide */
+    NetworkEvent() {
         //empty constructor
     }
 
-    protected NetworkEvent(String packageName, long timestamp) {
+    /** @hide */
+    NetworkEvent(String packageName, long timestamp) {
         this.packageName = packageName;
         this.timestamp = timestamp;
     }
 
-    /** Returns the package name of the UID that performed the query. */
+    /**
+     * Returns the package name of the UID that performed the query, as returned by
+     * {@link PackageManager#getNameForUid}.
+     */
     public String getPackageName() {
         return packageName;
     }
 
-    /** Returns the timestamp of the event being reported in milliseconds. */
+    /**
+     * Returns the timestamp of the event being reported in milliseconds, the difference between
+     * the time the event was reported and midnight, January 1, 1970 UTC.
+     */
     public long getTimestamp() {
         return timestamp;
     }
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 5162a73..ca3658b 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -853,14 +853,29 @@
      * @hide
      */
     public void prepareToLeaveProcess(boolean leavingPackage) {
+        prepareToLeaveProcess(leavingPackage, 0);
+    }
+
+    /**
+     * Prepare this {@link ClipData} to leave an app process.
+     *
+     * @hide
+     */
+    public void prepareToLeaveProcess(boolean leavingPackage, int intentFlags) {
         final int size = mItems.size();
         for (int i = 0; i < size; i++) {
             final Item item = mItems.get(i);
             if (item.mIntent != null) {
                 item.mIntent.prepareToLeaveProcess(leavingPackage);
             }
-            if (item.mUri != null && StrictMode.vmFileUriExposureEnabled() && leavingPackage) {
-                item.mUri.checkFileUriExposed("ClipData.Item.getUri()");
+            if (item.mUri != null && leavingPackage) {
+                if (StrictMode.vmFileUriExposureEnabled()) {
+                    item.mUri.checkFileUriExposed("ClipData.Item.getUri()");
+                }
+                if (StrictMode.vmContentUriWithoutPermissionEnabled()) {
+                    item.mUri.checkContentUriWithoutPermission("ClipData.Item.getUri()",
+                            intentFlags);
+                }
             }
         }
     }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 50589fe..cda8176 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3483,6 +3483,21 @@
     public static final String CATEGORY_OPENABLE = "android.intent.category.OPENABLE";
 
     /**
+     * Used to indicate that an intent filter can accept files which are not necessarily
+     * openable by {@link ContentResolver#openFileDescriptor(Uri, String)}, but
+     * at least streamable via
+     * {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)}
+     * using one of the stream types exposed via
+     * {@link ContentResolver#getStreamTypes(Uri, String)}.
+     *
+     * @see #ACTION_SEND
+     * @see #ACTION_SEND_MULTIPLE
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_TYPED_OPENABLE  =
+            "android.intent.category.TYPED_OPENABLE";
+
+    /**
      * To be used as code under test for framework instrumentation tests.
      */
     public static final String CATEGORY_FRAMEWORK_INSTRUMENTATION_TEST =
@@ -9009,7 +9024,7 @@
             mSelector.prepareToLeaveProcess(leavingPackage);
         }
         if (mClipData != null) {
-            mClipData.prepareToLeaveProcess(leavingPackage);
+            mClipData.prepareToLeaveProcess(leavingPackage, getFlags());
         }
 
         if (mAction != null && mData != null && StrictMode.vmFileUriExposureEnabled()
@@ -9036,6 +9051,17 @@
                     mData.checkFileUriExposed("Intent.getData()");
             }
         }
+
+        if (mAction != null && mData != null && StrictMode.vmContentUriWithoutPermissionEnabled()
+                && leavingPackage) {
+            switch (mAction) {
+                case ACTION_PROVIDER_CHANGED:
+                    // Ignore actions that don't need to grant
+                    break;
+                default:
+                    mData.checkContentUriWithoutPermission("Intent.getData()", getFlags());
+            }
+        }
     }
 
     /**
diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java
index 2beca7b..358787e 100644
--- a/core/java/android/content/pm/LauncherActivityInfo.java
+++ b/core/java/android/content/pm/LauncherActivityInfo.java
@@ -89,6 +89,7 @@
      * @return The label for the activity.
      */
     public CharSequence getLabel() {
+        // TODO: Go through LauncherAppsService
         return mActivityInfo.loadLabel(mPm);
     }
 
@@ -101,6 +102,7 @@
      * @return The drawable associated with the activity.
      */
     public Drawable getIcon(int density) {
+        // TODO: Go through LauncherAppsService
         final int iconRes = mActivityInfo.getIconResource();
         Drawable icon = null;
         // Get the preferred density icon from the app's resources
@@ -144,8 +146,9 @@
      */
     public long getFirstInstallTime() {
         try {
+            // TODO: Go through LauncherAppsService
             return mPm.getPackageInfo(mActivityInfo.packageName,
-                    PackageManager.GET_UNINSTALLED_PACKAGES).firstInstallTime;
+                    PackageManager.MATCH_UNINSTALLED_PACKAGES).firstInstallTime;
         } catch (NameNotFoundException nnfe) {
             // Sorry, can't find package
             return 0;
@@ -171,6 +174,7 @@
         Drawable originalIcon = getIcon(density);
 
         if (originalIcon instanceof BitmapDrawable) {
+            // TODO: Go through LauncherAppsService
             return mPm.getUserBadgedIcon(originalIcon, mUser);
         } else {
             Log.e(TAG, "Unable to create badged icon for " + mActivityInfo);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 6b23da9..7fc8044 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -447,12 +447,12 @@
     /**
      * Retrieve all of the information we know about a particular package / application.
      *
-     * @param packageName The package of the application
+     * @param packageName The package name of the application
      * @param flags Additional option flags {@link PackageManager#getApplicationInfo}
      * @param user The UserHandle of the profile.
      *
      * @return An {@link ApplicationInfo} containing information about the package or
-     *         null of the package isn't found.
+     *         null if the package isn't installed for the given user.
      * @hide
      */
     public ApplicationInfo getApplicationInfo(String packageName, @ApplicationInfoFlags int flags,
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index b3dd0e5..3f052d38 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -435,6 +435,20 @@
     public static final int MATCH_FACTORY_ONLY = 0x00200000;
 
     /**
+     * Allows querying of packages installed for any user, not just the specific one. This flag
+     * is only meant for use by apps that have INTERACT_ACROSS_USERS_FULL permission.
+     * @hide
+     */
+    public static final int MATCH_ANY_USER = 0x00400000;
+
+    /**
+     * Combination of MATCH_ANY_USER and MATCH_UNINSTALLED_PACKAGES to mean any known
+     * package.
+     * @hide
+     */
+    public static final int MATCH_KNOWN_PACKAGES = MATCH_UNINSTALLED_PACKAGES | MATCH_ANY_USER;
+
+    /**
      * Internal flag used to indicate that a system component has done their
      * homework and verified that they correctly handle packages and components
      * that come and go over time. In particular:
@@ -4522,32 +4536,6 @@
             throws NameNotFoundException;
 
     /**
-     * Returns a managed-user-style badged copy of the given drawable allowing the user to
-     * distinguish it from the original drawable.
-     * The caller can specify the location in the bounds of the drawable to be
-     * badged where the badge should be applied as well as the density of the
-     * badge to be used.
-     * <p>
-     * If the original drawable is a BitmapDrawable and the backing bitmap is
-     * mutable as per {@link android.graphics.Bitmap#isMutable()}, the badging
-     * is performed in place and the original drawable is returned.
-     * </p>
-     *
-     * @param drawable The drawable to badge.
-     * @param badgeLocation Where in the bounds of the badged drawable to place
-     *         the badge. If it's {@code null}, the badge is applied on top of the entire
-     *         drawable being badged.
-     * @param badgeDensity The optional desired density for the badge as per
-     *         {@link android.util.DisplayMetrics#densityDpi}. If it's not positive,
-     *         the density of the display is used.
-     * @return A drawable that combines the original drawable and a badge as
-     *         determined by the system.
-     * @hide
-     */
-    public abstract Drawable getManagedUserBadgedDrawable(Drawable drawable, Rect badgeLocation,
-        int badgeDensity);
-
-    /**
      * If the target user is a managed profile, then this returns a badged copy of the given icon
      * to be able to distinguish it from the original icon. For badging an arbitrary drawable use
      * {@link #getUserBadgedDrawableForDensity(
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index bb9c18a..f363bd8 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -478,20 +478,25 @@
     /**
      * Returns true if the package is installed and not hidden, or if the caller
      * explicitly wanted all uninstalled and hidden packages as well.
+     * @param appInfo The applicationInfo of the app being checked.
      */
-    private static boolean checkUseInstalledOrHidden(int flags, PackageUserState state) {
-        return (state.installed && !state.hidden)
-                || (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
+    private static boolean checkUseInstalledOrHidden(int flags, PackageUserState state,
+            ApplicationInfo appInfo) {
+        // If available for the target user, or trying to match uninstalled packages and it's
+        // a system app.
+        return state.isAvailable(flags)
+                || (appInfo != null && appInfo.isSystemApp()
+                        && (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0);
     }
 
     public static boolean isAvailable(PackageUserState state) {
-        return checkUseInstalledOrHidden(0, state);
+        return checkUseInstalledOrHidden(0, state, null);
     }
 
     public static PackageInfo generatePackageInfo(PackageParser.Package p,
             int gids[], int flags, long firstInstallTime, long lastUpdateTime,
             Set<String> grantedPermissions, PackageUserState state, int userId) {
-        if (!checkUseInstalledOrHidden(flags, state) || !p.isMatch(flags)) {
+        if (!checkUseInstalledOrHidden(flags, state, p.applicationInfo) || !p.isMatch(flags)) {
             return null;
         }
         PackageInfo pi = new PackageInfo();
@@ -1696,6 +1701,11 @@
         String str = sa.getNonConfigurationString(
                 com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
         if (str != null && str.length() > 0) {
+            if ((flags & PARSE_IS_EPHEMERAL) != 0) {
+                outError[0] = "sharedUserId not allowed in ephemeral application";
+                mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
+                return null;
+            }
             String nameError = validateName(str, true, false);
             if (nameError != null && !"android".equals(pkg.packageName)) {
                 outError[0] = "<manifest> specifies bad sharedUserId name \""
@@ -5445,7 +5455,7 @@
     public static ApplicationInfo generateApplicationInfo(Package p, int flags,
             PackageUserState state, int userId) {
         if (p == null) return null;
-        if (!checkUseInstalledOrHidden(flags, state) || !p.isMatch(flags)) {
+        if (!checkUseInstalledOrHidden(flags, state, p.applicationInfo) || !p.isMatch(flags)) {
             return null;
         }
         if (!copyNeeded(flags, p, state, null, userId)
@@ -5483,7 +5493,7 @@
     public static ApplicationInfo generateApplicationInfo(ApplicationInfo ai, int flags,
             PackageUserState state, int userId) {
         if (ai == null) return null;
-        if (!checkUseInstalledOrHidden(flags, state)) {
+        if (!checkUseInstalledOrHidden(flags, state, ai)) {
             return null;
         }
         // This is only used to return the ResolverActivity; we will just always
@@ -5549,7 +5559,7 @@
     public static final ActivityInfo generateActivityInfo(Activity a, int flags,
             PackageUserState state, int userId) {
         if (a == null) return null;
-        if (!checkUseInstalledOrHidden(flags, state)) {
+        if (!checkUseInstalledOrHidden(flags, state, a.owner.applicationInfo)) {
             return null;
         }
         if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) {
@@ -5565,7 +5575,7 @@
     public static final ActivityInfo generateActivityInfo(ActivityInfo ai, int flags,
             PackageUserState state, int userId) {
         if (ai == null) return null;
-        if (!checkUseInstalledOrHidden(flags, state)) {
+        if (!checkUseInstalledOrHidden(flags, state, ai.applicationInfo)) {
             return null;
         }
         // This is only used to return the ResolverActivity; we will just always
@@ -5603,7 +5613,7 @@
     public static final ServiceInfo generateServiceInfo(Service s, int flags,
             PackageUserState state, int userId) {
         if (s == null) return null;
-        if (!checkUseInstalledOrHidden(flags, state)) {
+        if (!checkUseInstalledOrHidden(flags, state, s.owner.applicationInfo)) {
             return null;
         }
         if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) {
@@ -5652,7 +5662,7 @@
     public static final ProviderInfo generateProviderInfo(Provider p, int flags,
             PackageUserState state, int userId) {
         if (p == null) return null;
-        if (!checkUseInstalledOrHidden(flags, state)) {
+        if (!checkUseInstalledOrHidden(flags, state, p.owner.applicationInfo)) {
             return null;
         }
         if (!copyNeeded(flags, p.owner, state, p.metaData, userId)
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 8ce8a13..1821458 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -29,7 +29,6 @@
 
 import android.util.ArraySet;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 
 /**
@@ -80,9 +79,14 @@
     /**
      * Test if this package is installed.
      */
-    public boolean isInstalled(int flags) {
-        return (this.installed && !this.hidden)
-                || (flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0;
+    public boolean isAvailable(int flags) {
+        // True if it is installed for this user and it is not hidden. If it is hidden,
+        // still return true if the caller requested MATCH_UNINSTALLED_PACKAGES
+        final boolean matchAnyUser = (flags & PackageManager.MATCH_ANY_USER) != 0;
+        final boolean matchUninstalled = (flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0;
+        return matchAnyUser
+                || (this.installed
+                        && (!this.hidden || matchUninstalled));
     }
 
     /**
@@ -95,11 +99,14 @@
      * </p>
      */
     public boolean isMatch(ComponentInfo componentInfo, int flags) {
-        if (!isInstalled(flags)) return false;
+        final boolean isSystemApp = componentInfo.applicationInfo.isSystemApp();
+        final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0;
+        if (!isAvailable(flags)
+                && !(isSystemApp && matchUninstalled)) return false;
         if (!isEnabled(componentInfo, flags)) return false;
 
         if ((flags & MATCH_SYSTEM_ONLY) != 0) {
-            if (!componentInfo.applicationInfo.isSystemApp()) {
+            if (!isSystemApp) {
                 return false;
             }
         }
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index a854b89..56f914e 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -314,9 +314,11 @@
      *
      * @hide
      */
-    public void enforceMandatoryFields() {
+    public void enforceMandatoryFields(boolean forPinned) {
         Preconditions.checkStringNotEmpty(mId, "Shortcut ID must be provided");
-        Preconditions.checkNotNull(mActivity, "Activity must be provided");
+        if (!forPinned) {
+            Preconditions.checkNotNull(mActivity, "Activity must be provided");
+        }
         if (mTitle == null && mTitleResId == 0) {
             throw new IllegalArgumentException("Short label must be provided");
         }
@@ -1055,6 +1057,11 @@
      * Launcher apps should show the launcher icon for the returned activity alongside
      * this shortcut.
      *
+     * <p>When a shortcut is dynamic or manifest
+     * (i.e. either {@link #isDynamic()} or {@link #isDeclaredInManifest()} returns {@code TRUE}),
+     * then it should always have a non-null target activity.
+     * Otherwise it will return null.
+     *
      * @see Builder#setActivity
      */
     @Nullable
@@ -1361,7 +1368,7 @@
     }
 
     /**
-     * @return true if pinned but neither static nor dynamic.
+     * Return {@code TRUE} if a shortcut is pinned but neither manifest nor dynamic.
      * @hide
      */
     public boolean isFloating() {
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index e796fa7..f34b590 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -109,6 +109,8 @@
      */
     public int profileGroupId;
     public int restrictedProfileParentId;
+    /** Which profile badge color/label to use. */
+    public int profileBadge;
 
     /** User is only partially created. */
     public boolean partial;
@@ -233,6 +235,7 @@
         profileGroupId = orig.profileGroupId;
         restrictedProfileParentId = orig.restrictedProfileParentId;
         guestToRemove = orig.guestToRemove;
+        profileBadge = orig.profileBadge;
     }
 
     public UserHandle getUserHandle() {
@@ -261,6 +264,7 @@
         dest.writeInt(profileGroupId);
         dest.writeInt(guestToRemove ? 1 : 0);
         dest.writeInt(restrictedProfileParentId);
+        dest.writeInt(profileBadge);
     }
 
     public static final Parcelable.Creator<UserInfo> CREATOR
@@ -286,5 +290,6 @@
         profileGroupId = source.readInt();
         guestToRemove = source.readInt() != 0;
         restrictedProfileParentId = source.readInt();
+        profileBadge = source.readInt();
     }
 }
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index b0d0d79..db24ffe 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -815,9 +815,9 @@
 
     /*package*/ static final int STYLE_DENSITY = 5;
     @FastNative
-    /*package*/ native static final boolean applyStyle(long theme,
+    /*package*/ native static final void applyStyle(long theme,
             int defStyleAttr, int defStyleRes, long xmlParser,
-            int[] inAttrs, int[] outValues, int[] outIndices);
+            int[] inAttrs, int length, long outValuesAddress, long outIndicesAddress);
     @FastNative
     /*package*/ native static final boolean resolveAttrs(long theme,
             int defStyleAttr, int defStyleRes, int[] inValues,
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index c46fe29..eb010e4 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -1126,7 +1126,7 @@
                 final XmlBlock.Parser parser = (XmlBlock.Parser) set;
                 AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
                         parser != null ? parser.mParseState : 0,
-                        attrs, array.mData, array.mIndices);
+                        attrs, attrs.length, array.mDataAddress, array.mIndicesAddress);
                 array.mTheme = wrapper;
                 array.mXml = parser;
 
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 1e44a5c..ca95ce1 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -30,6 +30,8 @@
 
 import com.android.internal.util.XmlUtils;
 
+import dalvik.system.VMRuntime;
+
 import java.util.Arrays;
 
 /**
@@ -44,28 +46,17 @@
 public class TypedArray {
 
     static TypedArray obtain(Resources res, int len) {
-        final TypedArray attrs = res.mTypedArrayPool.acquire();
-        if (attrs != null) {
-            attrs.mLength = len;
-            attrs.mRecycled = false;
-
-            // Reset the assets, which may have changed due to configuration changes
-            // or further resource loading.
-            attrs.mAssets = res.getAssets();
-
-            final int fullLen = len * AssetManager.STYLE_NUM_ENTRIES;
-            if (attrs.mData.length >= fullLen) {
-                return attrs;
-            }
-
-            attrs.mData = new int[fullLen];
-            attrs.mIndices = new int[1 + len];
-            return attrs;
+        TypedArray attrs = res.mTypedArrayPool.acquire();
+        if (attrs == null) {
+            attrs = new TypedArray(res);
         }
 
-        return new TypedArray(res,
-                new int[len*AssetManager.STYLE_NUM_ENTRIES],
-                new int[1+len], len);
+        attrs.mRecycled = false;
+        // Reset the assets, which may have changed due to configuration changes
+        // or further resource loading.
+        attrs.mAssets = res.getAssets();
+        attrs.resize(len);
+        return attrs;
     }
 
     private final Resources mResources;
@@ -77,10 +68,25 @@
     /*package*/ XmlBlock.Parser mXml;
     /*package*/ Resources.Theme mTheme;
     /*package*/ int[] mData;
+    /*package*/ long mDataAddress;
     /*package*/ int[] mIndices;
+    /*package*/ long mIndicesAddress;
     /*package*/ int mLength;
     /*package*/ TypedValue mValue = new TypedValue();
 
+    private void resize(int len) {
+        mLength = len;
+        final int dataLen = len * AssetManager.STYLE_NUM_ENTRIES;
+        final int indicesLen = len + 1;
+        final VMRuntime runtime = VMRuntime.getRuntime();
+        if (mData == null || mData.length < dataLen) {
+            mData = (int[]) runtime.newNonMovableArray(int.class, dataLen);
+            mDataAddress = runtime.addressOf(mData);
+            mIndices = (int[]) runtime.newNonMovableArray(int.class, indicesLen);
+            mIndicesAddress = runtime.addressOf(mIndices);
+        }
+    }
+
     /**
      * Returns the number of values in this array.
      *
@@ -1217,13 +1223,11 @@
         return mAssets.getPooledStringForCookie(cookie, data[index+AssetManager.STYLE_DATA]);
     }
 
-    /*package*/ TypedArray(Resources resources, int[] data, int[] indices, int len) {
+    /** @hide */
+    protected TypedArray(Resources resources) {
         mResources = resources;
         mMetrics = mResources.getDisplayMetrics();
         mAssets = mResources.getAssets();
-        mData = data;
-        mIndices = indices;
-        mLength = len;
     }
 
     @Override
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 9e00b65..45cd084 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -440,7 +440,7 @@
      */
     public abstract void createCaptureSessionByOutputConfigurations(
             List<OutputConfiguration> outputConfigurations,
-            CameraCaptureSession.StateCallback callback, Handler handler)
+            CameraCaptureSession.StateCallback callback, @Nullable Handler handler)
             throws CameraAccessException;
     /**
      * Create a new reprocessable camera capture session by providing the desired reprocessing
diff --git a/core/java/android/net/EventLogTags.logtags b/core/java/android/net/EventLogTags.logtags
new file mode 100644
index 0000000..d5ed014
--- /dev/null
+++ b/core/java/android/net/EventLogTags.logtags
@@ -0,0 +1,6 @@
+# See system/core/logcat/event.logtags for a description of the format of this file.
+
+option java_package android.net
+
+50080 ntp_success (server|3),(rtt|2),(offset|2)
+50081 ntp_failure (server|3),(msg|3)
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index c2286ad..a0f74ec 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -144,7 +144,7 @@
      *         scorer.
      */
     public String getActiveScorerPackage() {
-        NetworkScorerAppData app = NetworkScorerAppManager.getActiveScorer(mContext);
+        NetworkScorerAppData app = new NetworkScorerAppManager(mContext).getActiveScorer();
         if (app == null) {
             return null;
         }
diff --git a/core/java/android/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java
index 29291ca..ebb31c9 100644
--- a/core/java/android/net/NetworkScorerAppManager.java
+++ b/core/java/android/net/NetworkScorerAppManager.java
@@ -41,14 +41,17 @@
  *
  * @hide
  */
-public final class NetworkScorerAppManager {
+public class NetworkScorerAppManager {
     private static final String TAG = "NetworkScorerAppManager";
 
     private static final Intent SCORE_INTENT =
             new Intent(NetworkScoreManager.ACTION_SCORE_NETWORKS);
 
-    /** This class cannot be instantiated. */
-    private NetworkScorerAppManager() {}
+    private final Context mContext;
+
+    public NetworkScorerAppManager(Context context) {
+      mContext = context;
+    }
 
     public static class NetworkScorerAppData {
         /** Package name of this scorer app. */
@@ -108,7 +111,7 @@
      *
      * @return the list of scorers, or the empty list if there are no valid scorers.
      */
-    public static Collection<NetworkScorerAppData> getAllValidScorers(Context context) {
+    public Collection<NetworkScorerAppData> getAllValidScorers() {
         // Network scorer apps can only run as the primary user so exit early if we're not the
         // primary user.
         if (UserHandle.getCallingUserId() != UserHandle.USER_SYSTEM) {
@@ -116,7 +119,7 @@
         }
 
         List<NetworkScorerAppData> scorers = new ArrayList<>();
-        PackageManager pm = context.getPackageManager();
+        PackageManager pm = mContext.getPackageManager();
         // Only apps installed under the primary user of the device can be scorers.
         // TODO: http://b/23422763
         List<ResolveInfo> receivers =
@@ -179,10 +182,10 @@
      *     selected) or if the previously-set scorer is no longer a valid scorer app (e.g. because
      *     it was disabled or uninstalled).
      */
-    public static NetworkScorerAppData getActiveScorer(Context context) {
-        String scorerPackage = Settings.Global.getString(context.getContentResolver(),
+    public NetworkScorerAppData getActiveScorer() {
+        String scorerPackage = Settings.Global.getString(mContext.getContentResolver(),
                 Settings.Global.NETWORK_SCORER_APP);
-        return getScorer(context, scorerPackage);
+        return getScorer(scorerPackage);
     }
 
     /**
@@ -190,13 +193,12 @@
      *
      * <p>The caller must have permission to write to {@link android.provider.Settings.Global}.
      *
-     * @param context the context of the calling application
      * @param packageName the packageName of the new scorer to use. If null, scoring will be
      *     disabled. Otherwise, the scorer will only be set if it is a valid scorer application.
      * @return true if the scorer was changed, or false if the package is not a valid scorer.
      */
-    public static boolean setActiveScorer(Context context, String packageName) {
-        String oldPackageName = Settings.Global.getString(context.getContentResolver(),
+    public boolean setActiveScorer(String packageName) {
+        String oldPackageName = Settings.Global.getString(mContext.getContentResolver(),
                 Settings.Global.NETWORK_SCORER_APP);
         if (TextUtils.equals(oldPackageName, packageName)) {
             // No change.
@@ -206,13 +208,13 @@
         Log.i(TAG, "Changing network scorer from " + oldPackageName + " to " + packageName);
 
         if (packageName == null) {
-            Settings.Global.putString(context.getContentResolver(),
+            Settings.Global.putString(mContext.getContentResolver(),
                     Settings.Global.NETWORK_SCORER_APP, null);
             return true;
         } else {
             // We only make the change if the new package is valid.
-            if (getScorer(context, packageName) != null) {
-                Settings.Global.putString(context.getContentResolver(),
+            if (getScorer(packageName) != null) {
+                Settings.Global.putString(mContext.getContentResolver(),
                         Settings.Global.NETWORK_SCORER_APP, packageName);
                 return true;
             } else {
@@ -223,8 +225,8 @@
     }
 
     /** Determine whether the application with the given UID is the enabled scorer. */
-    public static boolean isCallerActiveScorer(Context context, int callingUid) {
-        NetworkScorerAppData defaultApp = getActiveScorer(context);
+    public boolean isCallerActiveScorer(int callingUid) {
+        NetworkScorerAppData defaultApp = getActiveScorer();
         if (defaultApp == null) {
             return false;
         }
@@ -233,16 +235,16 @@
         }
         // To be extra safe, ensure the caller holds the SCORE_NETWORKS permission. It always
         // should, since it couldn't become the active scorer otherwise, but this can't hurt.
-        return context.checkCallingPermission(Manifest.permission.SCORE_NETWORKS) ==
+        return mContext.checkCallingPermission(Manifest.permission.SCORE_NETWORKS) ==
                 PackageManager.PERMISSION_GRANTED;
     }
 
     /** Returns the {@link NetworkScorerAppData} for the given app, or null if it's not a scorer. */
-    public static NetworkScorerAppData getScorer(Context context, String packageName) {
+    public NetworkScorerAppData getScorer(String packageName) {
         if (TextUtils.isEmpty(packageName)) {
             return null;
         }
-        Collection<NetworkScorerAppData> applications = getAllValidScorers(context);
+        Collection<NetworkScorerAppData> applications = getAllValidScorers();
         for (NetworkScorerAppData app : applications) {
             if (packageName.equals(app.mPackageName)) {
                 return app;
diff --git a/core/java/android/net/SntpClient.java b/core/java/android/net/SntpClient.java
index cf9243f..cea56b5 100644
--- a/core/java/android/net/SntpClient.java
+++ b/core/java/android/net/SntpClient.java
@@ -36,8 +36,7 @@
  * }
  * </pre>
  */
-public class SntpClient
-{
+public class SntpClient {
     private static final String TAG = "SntpClient";
     private static final boolean DBG = true;
 
@@ -88,6 +87,7 @@
         try {
             address = InetAddress.getByName(host);
         } catch (Exception e) {
+            EventLogTags.writeNtpFailure(host, e.toString());
             if (DBG) Log.d(TAG, "request time failed: " + e);
             return false;
         }
@@ -142,6 +142,7 @@
             //             = (transit + skew - transit + skew)/2
             //             = (2 * skew)/2 = skew
             long clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime))/2;
+            EventLogTags.writeNtpSuccess(address.toString(), roundTripTime, clockOffset);
             if (DBG) {
                 Log.d(TAG, "round trip: " + roundTripTime + "ms, " +
                         "clock offset: " + clockOffset + "ms");
@@ -153,6 +154,7 @@
             mNtpTimeReference = responseTicks;
             mRoundTripTime = roundTripTime;
         } catch (Exception e) {
+            EventLogTags.writeNtpFailure(address.toString(), e.toString());
             if (DBG) Log.d(TAG, "request time failed: " + e);
             return false;
         } finally {
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 67378bd..7396189 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.content.Intent;
 import android.os.Environment;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -2342,12 +2343,25 @@
      * @hide
      */
     public void checkFileUriExposed(String location) {
-        if ("file".equals(getScheme()) && !getPath().startsWith("/system/")) {
+        if ("file".equals(getScheme())
+                && (getPath() != null) && !getPath().startsWith("/system/")) {
             StrictMode.onFileUriExposed(this, location);
         }
     }
 
     /**
+     * If this is a {@code content://} Uri without access flags, it will be
+     * reported to {@link StrictMode}.
+     *
+     * @hide
+     */
+    public void checkContentUriWithoutPermission(String location, int flags) {
+        if ("content".equals(getScheme()) && !Intent.isAccessUriMode(flags)) {
+            StrictMode.onContentUriWithoutPermission(this, location);
+        }
+    }
+
+    /**
      * Test if this is a path prefix match against the given Uri. Verifies that
      * scheme, authority, and atomic path segments match.
      *
diff --git a/core/java/android/net/metrics/NetworkEvent.java b/core/java/android/net/metrics/NetworkEvent.java
index 3b3fa69..0667495 100644
--- a/core/java/android/net/metrics/NetworkEvent.java
+++ b/core/java/android/net/metrics/NetworkEvent.java
@@ -42,6 +42,15 @@
     public static final int NETWORK_DISCONNECTED         = 7;
 
     /** {@hide} */
+    public static final int NETWORK_FIRST_VALIDATION_SUCCESS      = 8;
+    /** {@hide} */
+    public static final int NETWORK_REVALIDATION_SUCCESS          = 9;
+    /** {@hide} */
+    public static final int NETWORK_FIRST_VALIDATION_PORTAL_FOUND = 10;
+    /** {@hide} */
+    public static final int NETWORK_REVALIDATION_PORTAL_FOUND     = 11;
+
+    /** {@hide} */
     @IntDef(value = {
             NETWORK_CONNECTED,
             NETWORK_VALIDATED,
@@ -50,6 +59,10 @@
             NETWORK_LINGER,
             NETWORK_UNLINGER,
             NETWORK_DISCONNECTED,
+            NETWORK_FIRST_VALIDATION_SUCCESS,
+            NETWORK_REVALIDATION_SUCCESS,
+            NETWORK_FIRST_VALIDATION_PORTAL_FOUND,
+            NETWORK_REVALIDATION_PORTAL_FOUND,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface EventType {}
diff --git a/core/java/android/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java
index 1a31b56..a724ec1 100644
--- a/core/java/android/net/metrics/ValidationProbeEvent.java
+++ b/core/java/android/net/metrics/ValidationProbeEvent.java
@@ -44,10 +44,8 @@
     public static final int DNS_FAILURE = 0;
     public static final int DNS_SUCCESS = 1;
 
-    /** {@hide} */
-    @IntDef(value = {PROBE_DNS, PROBE_HTTP, PROBE_HTTPS, PROBE_PAC})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface ProbeType {}
+    private static final int FIRST_VALIDATION  = 1 << 8;
+    private static final int REVALIDATION      = 2 << 8;
 
     /** {@hide} */
     @IntDef(value = {DNS_FAILURE, DNS_SUCCESS})
@@ -56,12 +54,17 @@
 
     public final int netId;
     public final long durationMs;
-    public final @ProbeType int probeType;
+    // probeType byte format (MSB to LSB):
+    // byte 0: unused
+    // byte 1: unused
+    // byte 2: 0 = UNKNOWN, 1 = FIRST_VALIDATION, 2 = REVALIDATION
+    // byte 3: PROBE_* constant
+    public final int probeType;
     public final @ReturnCode int returnCode;
 
     /** {@hide} */
     public ValidationProbeEvent(
-            int netId, long durationMs, @ProbeType int probeType, @ReturnCode int returnCode) {
+            int netId, long durationMs, int probeType, @ReturnCode int returnCode) {
         this.netId = netId;
         this.durationMs = durationMs;
         this.probeType = probeType;
@@ -100,8 +103,18 @@
     };
 
     /** @hide */
+    public static int makeProbeType(int probeType, boolean firstValidation) {
+        return (probeType & 0xff) | (firstValidation ? FIRST_VALIDATION : REVALIDATION);
+    }
+
+    /** @hide */
     public static String getProbeName(int probeType) {
-        return Decoder.constants.get(probeType, "PROBE_???");
+        return Decoder.constants.get(probeType & 0xff, "PROBE_???");
+    }
+
+    /** @hide */
+    public static String getValidationStage(int probeType) {
+        return Decoder.constants.get(probeType & 0xff00, "UNKNOWN");
     }
 
     public static void logEvent(int netId, long durationMs, int probeType, int returnCode) {
@@ -109,12 +122,13 @@
 
     @Override
     public String toString() {
-        return String.format("ValidationProbeEvent(%d, %s:%d, %dms)",
-                netId, getProbeName(probeType), returnCode, durationMs);
+        return String.format("ValidationProbeEvent(%d, %s:%d %s, %dms)", netId,
+                getProbeName(probeType), returnCode, getValidationStage(probeType), durationMs);
     }
 
     final static class Decoder {
         static final SparseArray<String> constants = MessageUtils.findMessageNames(
-                new Class[]{ValidationProbeEvent.class}, new String[]{"PROBE_"});
+                new Class[]{ValidationProbeEvent.class},
+                new String[]{"PROBE_", "FIRST_", "REVALIDATION"});
     }
 }
diff --git a/core/java/android/os/IProxyFileDescriptorCallback.java b/core/java/android/os/IProxyFileDescriptorCallback.java
new file mode 100644
index 0000000..e41e194
--- /dev/null
+++ b/core/java/android/os/IProxyFileDescriptorCallback.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.system.ErrnoException;
+
+/**
+ * Callback that handles file system requests from ProxyFileDescriptor.
+ * @hide
+ */
+public interface IProxyFileDescriptorCallback {
+    /**
+     * Returns size of bytes provided by the file descriptor.
+     * @return Size of bytes
+     * @throws ErrnoException
+     */
+    long onGetSize() throws ErrnoException;
+
+    /**
+     * Provides bytes read from file descriptor.
+     * It needs to return exact requested size of bytes unless it reaches file end.
+     * @param offset Where to read bytes from.
+     * @param size Size for read bytes.
+     * @param data Byte array to store read bytes.
+     * @return Size of bytes returned by the function.
+     * @throws ErrnoException
+     */
+    int onRead(long offset, int size, byte[] data) throws ErrnoException;
+
+    /**
+     * Handles bytes written to file descriptor.
+     * @param offset Where to write bytes to.
+     * @param size Size for write bytes.
+     * @param data Byte array to be written to somewhere.
+     * @return Size of bytes processed by the function.
+     * @throws ErrnoException
+     */
+    int onWrite(long offset, int size, byte[] data) throws ErrnoException;
+
+    /**
+     * Processes fsync request.
+     * @throws ErrnoException
+     */
+    void onFsync() throws ErrnoException;
+}
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 65c6093..d443b66 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -86,4 +86,7 @@
     UserInfo createProfileForUserEvenWhenDisallowed(in String name, int flags, int userHandle,
             in String[] disallowedPackages);
     boolean isUserUnlockingOrUnlocked(int userId);
+    int getManagedProfileBadge(int userId);
+    boolean isUserUnlocked(int userId);
+    boolean isUserRunning(int userId);
 }
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 85f999b..e15f086 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -1297,6 +1297,29 @@
     }
 
     /**
+     * Flatten a {@code List} containing arbitrary {@code Parcelable} objects into this parcel
+     * at the current position. They can later be retrieved using
+     * {@link #readParcelableList(List, ClassLoader)} if required.
+     *
+     * @see #readParcelableList(List, ClassLoader)
+     * @hide
+     */
+    public final <T extends Parcelable> void writeParcelableList(List<T> val, int flags) {
+        if (val == null) {
+            writeInt(-1);
+            return;
+        }
+
+        int N = val.size();
+        int i=0;
+        writeInt(N);
+        while (i < N) {
+            writeParcelable(val.get(i), flags);
+            i++;
+        }
+    }
+
+    /**
      * Flatten a heterogeneous array containing a particular object type into
      * the parcel, at
      * the current dataPosition() and growing dataCapacity() if needed.  The
@@ -2244,9 +2267,6 @@
      * Read into the given List items IBinder objects that were written with
      * {@link #writeBinderList} at the current dataPosition().
      *
-     * @return A newly created ArrayList containing strings with the same data
-     *         as those that were previously written.
-     *
      * @see #writeBinderList
      */
     public final void readBinderList(List<IBinder> list) {
@@ -2265,6 +2285,34 @@
     }
 
     /**
+     * Read the list of {@code Parcelable} objects at the current data position into the
+     * given {@code list}. The contents of the {@code list} are replaced. If the serialized
+     * list was {@code null}, {@code list} is cleared.
+     *
+     * @see #writeParcelableList(List, int)
+     * @hide
+     */
+    public final <T extends Parcelable> void readParcelableList(List<T> list, ClassLoader cl) {
+        final int N = readInt();
+        if (N == -1) {
+            list.clear();
+            return;
+        }
+
+        final int M = list.size();
+        int i = 0;
+        for (; i < M && i < N; i++) {
+            list.set(i, (T) readParcelable(cl));
+        }
+        for (; i<N; i++) {
+            list.add((T) readParcelable(cl));
+        }
+        for (; i<M; i++) {
+            list.remove(N);
+        }
+    }
+
+    /**
      * Read and return a new array containing a particular object type from
      * the parcel at the current dataPosition().  Returns null if the
      * previously written array was null.  The array <em>must</em> have
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index ef79b66..f2519be 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -1800,6 +1800,13 @@
     /**
      * @hide
      */
+    public static boolean vmContentUriWithoutPermissionEnabled() {
+        return (sVmPolicyMask & DETECT_VM_FILE_URI_EXPOSURE) != 0;
+    }
+
+    /**
+     * @hide
+     */
     public static boolean vmCleartextNetworkEnabled() {
         return (sVmPolicyMask & DETECT_VM_CLEARTEXT_NETWORK) != 0;
     }
@@ -1847,6 +1854,16 @@
     /**
      * @hide
      */
+    public static void onContentUriWithoutPermission(Uri uri, String location) {
+        final String message = uri + " exposed beyond app through " + location
+                + " without permission grant flags; did you forget"
+                + " FLAG_GRANT_READ_URI_PERMISSION?";
+        onVmPolicyViolation(null, new Throwable(message));
+    }
+
+    /**
+     * @hide
+     */
     public static void onCleartextNetworkDetected(byte[] firstPacket) {
         byte[] rawAddr = null;
         if (firstPacket != null) {
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 50eb7cf..0d3b328 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -187,6 +187,8 @@
      * Specifies if a user is disallowed from configuring bluetooth.
      * This does <em>not</em> restrict the user from turning bluetooth on or off.
      * The default value is <code>false</code>.
+     * <p>This restriction doesn't prevent the user from using bluetooth. For disallowing usage of
+     * bluetooth completely on the device, use {@link #DISALLOW_BLUETOOTH}.
      * <p>This restriction has no effect in a managed profile.
      *
      * <p>Key for user restrictions.
@@ -198,6 +200,20 @@
     public static final String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
 
     /**
+     * Specifies if bluetooth is disallowed on the device.
+     *
+     * <p> This restriction can only be set by the device owner and the profile owner on the
+     * primary user and it applies globally - i.e. it disables bluetooth on the entire device.
+     * <p>The default value is <code>false</code>.
+     * <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_BLUETOOTH = "no_bluetooth";
+
+    /**
      * Specifies if a user is disallowed from transferring files over
      * USB. This can only be set by device owners and profile owners on the primary user.
      * The default value is <code>false</code>.
@@ -948,6 +964,23 @@
     }
 
     /**
+     * Gets badge for a managed profile.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission, otherwise the caller
+     * must be in the same profile group of specified user.
+     *
+     * @return which badge to use for the managed profile badge id will be less than
+     *         UserManagerService.getMaxManagedProfiles()
+     * @hide
+     */
+    public int getManagedProfileBadge(@UserIdInt int userId) {
+        try {
+            return mService.getManagedProfileBadge(userId);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Checks if the calling app is running as an ephemeral user.
      *
      * @return whether the caller is an ephemeral user.
@@ -979,10 +1012,9 @@
     }
 
     /** {@hide} */
-    public boolean isUserRunning(int userId) {
-        // TODO Switch to using UMS internal isUserRunning
+    public boolean isUserRunning(@UserIdInt int userId) {
         try {
-            return ActivityManager.getService().isUserRunning(userId, 0);
+            return mService.isUserRunning(userId);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
@@ -1079,8 +1111,7 @@
     /** {@hide} */
     public boolean isUserUnlocked(@UserIdInt int userId) {
         try {
-            return ActivityManager.getService().isUserRunning(userId,
-                    ActivityManager.FLAG_AND_UNLOCKED);
+            return mService.isUserUnlocked(userId);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java
index 4bdb92b..1447e7d 100644
--- a/core/java/android/os/UserManagerInternal.java
+++ b/core/java/android/os/UserManagerInternal.java
@@ -142,6 +142,12 @@
     public abstract boolean isUserUnlockingOrUnlocked(int userId);
 
     /**
+     * Return whether the given user is running in an
+     * {@code UserState.STATE_RUNNING_UNLOCKED} state.
+     */
+    public abstract boolean isUserUnlocked(int userId);
+
+    /**
      * Return whether the given user is running
      */
     public abstract boolean isUserRunning(int userId);
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 98cbce6..27c0526 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -288,4 +288,5 @@
     ParcelFileDescriptor mountAppFuse(in String name) = 69;
     void addUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 70;
     void fixateNewestUserKeyAuth(int userId) = 71;
-}
\ No newline at end of file
+    void fstrim(int flags) = 72;
+}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 0472e02..3fc7dba 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -134,6 +134,11 @@
     /** {@hide} */
     public static final int FLAG_INCLUDE_INVISIBLE = 1 << 10;
 
+    /** {@hide} */
+    public static final int FSTRIM_FLAG_DEEP = 1 << 0;
+    /** {@hide} */
+    public static final int FSTRIM_FLAG_BENCHMARK = 1 << 1;
+
     /** @hide The volume is not encrypted. */
     public static final int ENCRYPTION_STATE_NONE = 1;
 
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 2bfe33b..8303bca 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -21,6 +21,7 @@
 
 import android.annotation.DrawableRes;
 import android.annotation.LayoutRes;
+import android.annotation.Nullable;
 import android.annotation.StringRes;
 import android.content.Context;
 import android.content.Intent;
@@ -88,9 +89,19 @@
     public static final int DEFAULT_ORDER = Integer.MAX_VALUE;
 
     private Context mContext;
+
+    @Nullable
     private PreferenceManager mPreferenceManager;
 
     /**
+     * The data store that should be used by this Preference to store / retrieve data. If null then
+     * {@link PreferenceManager#getPreferenceDataStore()} needs to be checked. If that one is null
+     * too it means that we are using {@link android.content.SharedPreferences} to store the data.
+     */
+    @Nullable
+    private PreferenceDataStore mPreferenceDataStore;
+
+    /**
      * Set when added to hierarchy since we need a unique ID within that
      * hierarchy.
      */
@@ -395,6 +406,36 @@
     }
 
     /**
+     * Sets a {@link PreferenceDataStore} to be used by this Preference instead of using
+     * {@link android.content.SharedPreferences}.
+     * <p>
+     * The data store will remain assigned even if the Preference is moved between multiple
+     * instances of {@link PreferenceFragment}.
+     *
+     * @param dataStore The {@link PreferenceDataStore} to be used by this Preference.
+     */
+    public void setPreferenceDataStore(PreferenceDataStore dataStore) {
+        mPreferenceDataStore = dataStore;
+    }
+
+    /**
+     * Returns {@link PreferenceDataStore} used by this Preference. Returns {@code null} if
+     * {@link android.content.SharedPreferences} is used instead.
+     *
+     * @return The {@link PreferenceDataStore} used by this Preference or {@code null} if none.
+     */
+    @Nullable
+    public PreferenceDataStore getPreferenceDataStore() {
+        if (mPreferenceDataStore != null) {
+            return mPreferenceDataStore;
+        } else if (mPreferenceManager != null) {
+            return mPreferenceManager.getPreferenceDataStore();
+        }
+
+        return null;
+    }
+
+    /**
      * Return the extras Bundle object associated with this preference, creating
      * a new Bundle if there currently isn't one.  You can use this to get and
      * set individual extra key/value pairs.
@@ -1426,44 +1467,42 @@
     }
 
     /**
-     * Attempts to persist a String to the {@link android.content.SharedPreferences}.
-     * <p>
-     * This will check if this Preference is persistent, get an editor from
-     * the {@link PreferenceManager}, put in the string, and check if we should commit (and
-     * commit if so).
+     * Attempts to persist a String if this Preference is persistent.
      *
      * @param value The value to persist.
-     * @return True if the Preference is persistent. (This is not whether the
+     * @return True if this Preference is persistent. (This is not whether the
      *         value was persisted, since we may not necessarily commit if there
      *         will be a batch commit later.)
      * @see #getPersistedString(String)
      */
     protected boolean persistString(String value) {
-        if (shouldPersist()) {
-            // Shouldn't store null
-            if (TextUtils.equals(value, getPersistedString(null))) {
-                // It's already there, so the same as persisting
-                return true;
-            }
+        if (!shouldPersist()) {
+            return false;
+        }
 
+        // Shouldn't store null
+        if (TextUtils.equals(value, getPersistedString(null))) {
+            // It's already there, so the same as persisting
+            return true;
+        }
+
+        PreferenceDataStore dataStore = getPreferenceDataStore();
+        if (dataStore != null) {
+            dataStore.putString(mKey, value);
+        } else {
             SharedPreferences.Editor editor = mPreferenceManager.getEditor();
             editor.putString(mKey, value);
             tryCommit(editor);
-            return true;
         }
-        return false;
+        return true;
     }
 
     /**
-     * Attempts to get a persisted String from the {@link android.content.SharedPreferences}.
-     * <p>
-     * This will check if this Preference is persistent, get the SharedPreferences
-     * from the {@link PreferenceManager}, and get the value.
+     * Attempts to get a persisted String if this Preference is persistent.
      *
-     * @param defaultReturnValue The default value to return if either the
-     *            Preference is not persistent or the Preference is not in the
-     *            shared preferences.
-     * @return The value from the SharedPreferences or the default return
+     * @param defaultReturnValue The default value to return if either this
+     *            Preference is not persistent or this Preference is not present.
+     * @return The value from the data store or the default return
      *         value.
      * @see #persistString(String)
      */
@@ -1472,49 +1511,51 @@
             return defaultReturnValue;
         }
 
+        PreferenceDataStore dataStore = getPreferenceDataStore();
+        if (dataStore != null) {
+            return dataStore.getString(mKey, defaultReturnValue);
+        }
+
         return mPreferenceManager.getSharedPreferences().getString(mKey, defaultReturnValue);
     }
 
     /**
-     * Attempts to persist a set of Strings to the {@link android.content.SharedPreferences}.
-     * <p>
-     * This will check if this Preference is persistent, get an editor from
-     * the {@link PreferenceManager}, put in the strings, and check if we should commit (and
-     * commit if so).
+     * Attempts to persist a set of Strings if this Preference is persistent.
      *
      * @param values The values to persist.
-     * @return True if the Preference is persistent. (This is not whether the
+     * @return True if this Preference is persistent. (This is not whether the
      *         value was persisted, since we may not necessarily commit if there
      *         will be a batch commit later.)
      * @see #getPersistedStringSet(Set)
      */
-    public boolean persistStringSet(Set<String> values) {
-        if (shouldPersist()) {
-            // Shouldn't store null
-            if (values.equals(getPersistedStringSet(null))) {
-                // It's already there, so the same as persisting
-                return true;
-            }
+    public boolean persistStringSet(Set<String>  values) {
+        if (!shouldPersist()) {
+            return false;
+        }
 
+        // Shouldn't store null
+        if (values.equals(getPersistedStringSet(null))) {
+            // It's already there, so the same as persisting
+            return true;
+        }
+
+        PreferenceDataStore dataStore = getPreferenceDataStore();
+        if (dataStore != null) {
+            dataStore.putStringSet(mKey, values);
+        } else {
             SharedPreferences.Editor editor = mPreferenceManager.getEditor();
             editor.putStringSet(mKey, values);
             tryCommit(editor);
-            return true;
         }
-        return false;
+        return true;
     }
 
     /**
-     * Attempts to get a persisted set of Strings from the
-     * {@link android.content.SharedPreferences}.
-     * <p>
-     * This will check if this Preference is persistent, get the SharedPreferences
-     * from the {@link PreferenceManager}, and get the value.
+     * Attempts to get a persisted set of Strings if this Preference is persistent.
      *
-     * @param defaultReturnValue The default value to return if either the
-     *            Preference is not persistent or the Preference is not in the
-     *            shared preferences.
-     * @return The value from the SharedPreferences or the default return
+     * @param defaultReturnValue The default value to return if either this
+     *            Preference is not persistent or this Preference is not present.
+     * @return The value from the data store or the default return
      *         value.
      * @see #persistStringSet(Set)
      */
@@ -1523,41 +1564,51 @@
             return defaultReturnValue;
         }
 
+        PreferenceDataStore dataStore = getPreferenceDataStore();
+        if (dataStore != null) {
+            return dataStore.getStringSet(mKey, defaultReturnValue);
+        }
+
         return mPreferenceManager.getSharedPreferences().getStringSet(mKey, defaultReturnValue);
     }
 
     /**
-     * Attempts to persist an int to the {@link android.content.SharedPreferences}.
+     * Attempts to persist an int if this Preference is persistent.
      *
      * @param value The value to persist.
-     * @return True if the Preference is persistent. (This is not whether the
+     * @return True if this Preference is persistent. (This is not whether the
      *         value was persisted, since we may not necessarily commit if there
      *         will be a batch commit later.)
      * @see #persistString(String)
      * @see #getPersistedInt(int)
      */
     protected boolean persistInt(int value) {
-        if (shouldPersist()) {
-            if (value == getPersistedInt(~value)) {
-                // It's already there, so the same as persisting
-                return true;
-            }
+        if (!shouldPersist()) {
+            return false;
+        }
 
+        if (value == getPersistedInt(~value)) {
+            // It's already there, so the same as persisting
+            return true;
+        }
+
+        PreferenceDataStore dataStore = getPreferenceDataStore();
+        if (dataStore != null) {
+            dataStore.putInt(mKey, value);
+        } else {
             SharedPreferences.Editor editor = mPreferenceManager.getEditor();
             editor.putInt(mKey, value);
             tryCommit(editor);
-            return true;
         }
-        return false;
+        return true;
     }
 
     /**
-     * Attempts to get a persisted int from the {@link android.content.SharedPreferences}.
+     * Attempts to get a persisted int if this Preference is persistent.
      *
      * @param defaultReturnValue The default value to return if either this
-     *            Preference is not persistent or this Preference is not in the
-     *            SharedPreferences.
-     * @return The value from the SharedPreferences or the default return
+     *            Preference is not persistent or this Preference is not present.
+     * @return The value from the data store or the default return
      *         value.
      * @see #getPersistedString(String)
      * @see #persistInt(int)
@@ -1567,11 +1618,16 @@
             return defaultReturnValue;
         }
 
+        PreferenceDataStore dataStore = getPreferenceDataStore();
+        if (dataStore != null) {
+            return dataStore.getInt(mKey, defaultReturnValue);
+        }
+
         return mPreferenceManager.getSharedPreferences().getInt(mKey, defaultReturnValue);
     }
 
     /**
-     * Attempts to persist a float to the {@link android.content.SharedPreferences}.
+     * Attempts to persist a long if this Preference is persistent.
      *
      * @param value The value to persist.
      * @return True if this Preference is persistent. (This is not whether the
@@ -1581,27 +1637,32 @@
      * @see #getPersistedFloat(float)
      */
     protected boolean persistFloat(float value) {
-        if (shouldPersist()) {
-            if (value == getPersistedFloat(Float.NaN)) {
-                // It's already there, so the same as persisting
-                return true;
-            }
+        if (!shouldPersist()) {
+            return false;
+        }
 
+        if (value == getPersistedFloat(Float.NaN)) {
+            // It's already there, so the same as persisting
+            return true;
+        }
+
+        PreferenceDataStore dataStore = getPreferenceDataStore();
+        if (dataStore != null) {
+            dataStore.putFloat(mKey, value);
+        } else {
             SharedPreferences.Editor editor = mPreferenceManager.getEditor();
             editor.putFloat(mKey, value);
             tryCommit(editor);
-            return true;
         }
-        return false;
+        return true;
     }
 
     /**
-     * Attempts to get a persisted float from the {@link android.content.SharedPreferences}.
+     * Attempts to get a persisted float if this Preference is persistent.
      *
      * @param defaultReturnValue The default value to return if either this
-     *            Preference is not persistent or this Preference is not in the
-     *            SharedPreferences.
-     * @return The value from the SharedPreferences or the default return
+     *            Preference is not persistent or this Preference is not present.
+     * @return The value from the data store or the default return
      *         value.
      * @see #getPersistedString(String)
      * @see #persistFloat(float)
@@ -1611,11 +1672,16 @@
             return defaultReturnValue;
         }
 
+        PreferenceDataStore dataStore = getPreferenceDataStore();
+        if (dataStore != null) {
+            return dataStore.getFloat(mKey, defaultReturnValue);
+        }
+
         return mPreferenceManager.getSharedPreferences().getFloat(mKey, defaultReturnValue);
     }
 
     /**
-     * Attempts to persist a long to the {@link android.content.SharedPreferences}.
+     * Attempts to persist a long if this Preference is persistent.
      *
      * @param value The value to persist.
      * @return True if this Preference is persistent. (This is not whether the
@@ -1625,27 +1691,32 @@
      * @see #getPersistedLong(long)
      */
     protected boolean persistLong(long value) {
-        if (shouldPersist()) {
-            if (value == getPersistedLong(~value)) {
-                // It's already there, so the same as persisting
-                return true;
-            }
+        if (!shouldPersist()) {
+            return false;
+        }
 
+        if (value == getPersistedLong(~value)) {
+            // It's already there, so the same as persisting
+            return true;
+        }
+
+        PreferenceDataStore dataStore = getPreferenceDataStore();
+        if (dataStore != null) {
+            dataStore.putLong(mKey, value);
+        } else {
             SharedPreferences.Editor editor = mPreferenceManager.getEditor();
             editor.putLong(mKey, value);
             tryCommit(editor);
-            return true;
         }
-        return false;
+        return true;
     }
 
     /**
-     * Attempts to get a persisted long from the {@link android.content.SharedPreferences}.
+     * Attempts to get a persisted long if this Preference is persistent.
      *
      * @param defaultReturnValue The default value to return if either this
-     *            Preference is not persistent or this Preference is not in the
-     *            SharedPreferences.
-     * @return The value from the SharedPreferences or the default return
+     *            Preference is not persistent or this Preference is not present.
+     * @return The value from the data store or the default return
      *         value.
      * @see #getPersistedString(String)
      * @see #persistLong(long)
@@ -1655,11 +1726,16 @@
             return defaultReturnValue;
         }
 
+        PreferenceDataStore dataStore = getPreferenceDataStore();
+        if (dataStore != null) {
+            return dataStore.getLong(mKey, defaultReturnValue);
+        }
+
         return mPreferenceManager.getSharedPreferences().getLong(mKey, defaultReturnValue);
     }
 
     /**
-     * Attempts to persist a boolean to the {@link android.content.SharedPreferences}.
+     * Attempts to persist a boolean if this Preference is persistent.
      *
      * @param value The value to persist.
      * @return True if this Preference is persistent. (This is not whether the
@@ -1669,27 +1745,32 @@
      * @see #getPersistedBoolean(boolean)
      */
     protected boolean persistBoolean(boolean value) {
-        if (shouldPersist()) {
-            if (value == getPersistedBoolean(!value)) {
-                // It's already there, so the same as persisting
-                return true;
-            }
+        if (!shouldPersist()) {
+            return false;
+        }
 
+        if (value == getPersistedBoolean(!value)) {
+            // It's already there, so the same as persisting
+            return true;
+        }
+
+        PreferenceDataStore dataStore = getPreferenceDataStore();
+        if (dataStore != null) {
+            dataStore.putBoolean(mKey, value);
+        } else {
             SharedPreferences.Editor editor = mPreferenceManager.getEditor();
             editor.putBoolean(mKey, value);
             tryCommit(editor);
-            return true;
         }
-        return false;
+        return true;
     }
 
     /**
-     * Attempts to get a persisted boolean from the {@link android.content.SharedPreferences}.
+     * Attempts to get a persisted boolean if this Preference is persistent.
      *
      * @param defaultReturnValue The default value to return if either this
-     *            Preference is not persistent or this Preference is not in the
-     *            SharedPreferences.
-     * @return The value from the SharedPreferences or the default return
+     *            Preference is not persistent or this Preference is not present.
+     * @return The value from the data store or the default return
      *         value.
      * @see #getPersistedString(String)
      * @see #persistBoolean(boolean)
@@ -1699,6 +1780,11 @@
             return defaultReturnValue;
         }
 
+        PreferenceDataStore dataStore = getPreferenceDataStore();
+        if (dataStore != null) {
+            return dataStore.getBoolean(mKey, defaultReturnValue);
+        }
+
         return mPreferenceManager.getSharedPreferences().getBoolean(mKey, defaultReturnValue);
     }
 
diff --git a/core/java/android/preference/PreferenceDataStore.java b/core/java/android/preference/PreferenceDataStore.java
new file mode 100644
index 0000000..e1a08ac
--- /dev/null
+++ b/core/java/android/preference/PreferenceDataStore.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.preference;
+
+import android.annotation.Nullable;
+
+import java.util.Set;
+
+/**
+ * A data store interface to be implemented and provided to the Preferences framework.
+ *
+ * Use this to replace the default {@link android.content.SharedPreferences}. By default, all "put"
+ * methods throw {@link UnsupportedOperationException}.
+ */
+public interface PreferenceDataStore {
+
+    /**
+     * Set a String value to the data store.
+     *
+     * @param key The name of the preference to modify.
+     * @param value The new value for the preference.
+     * @see #getString(String, String)
+     */
+    default void putString(String key, @Nullable String value) {
+        throw new UnsupportedOperationException("Not implemented on this data store");
+    }
+
+    /**
+     * Set a set of String value to the data store.
+     *
+     * @param key The name of the preference to modify.
+     * @param values The set of new values for the preference.
+     * @see #getStringSet(String, Set)
+     */
+    default void putStringSet(String key, @Nullable Set<String> values) {
+        throw new UnsupportedOperationException("Not implemented on this data store");
+    }
+
+    /**
+     * Set an int value to the data store.
+     *
+     * @param key The name of the preference to modify.
+     * @param value The new value for the preference.
+     * @see #getInt(String, int)
+     */
+    default void putInt(String key, int value) {
+        throw new UnsupportedOperationException("Not implemented on this data store");
+    }
+
+    /**
+     * Set a long value to the data store.
+     *
+     * @param key The name of the preference to modify.
+     * @param value The new value for the preference.
+     * @see #getLong(String, long)
+     */
+    default void putLong(String key, long value) {
+        throw new UnsupportedOperationException("Not implemented on this data store");
+    }
+
+    /**
+     * Set a float value to the data store.
+     *
+     * @param key The name of the preference to modify.
+     * @param value The new value for the preference.
+     * @see #getFloat(String, float)
+     */
+    default void putFloat(String key, float value) {
+        throw new UnsupportedOperationException("Not implemented on this data store");
+    }
+
+    /**
+     * Set a boolean value to the data store.
+     *
+     * @param key The name of the preference to modify.
+     * @param value The new value for the preference.
+     * @see #getBoolean(String, boolean)
+     */
+    default void putBoolean(String key, boolean value) {
+        throw new UnsupportedOperationException("Not implemented on this data store");
+    }
+
+    /**
+     * Retrieve a String value from the data store.
+     *
+     * @param key The name of the preference to retrieve.
+     * @param defValue Value to return if this preference does not exist.
+     * @see #putString(String, String)
+     */
+    @Nullable
+    default String getString(String key, @Nullable String defValue) {
+        return defValue;
+    }
+
+    /**
+     * Retrieve a set of String values from the data store.
+     *
+     * @param key The name of the preference to retrieve.
+     * @param defValues Values to return if this preference does not exist.
+     * @see #putStringSet(String, Set)
+     */
+    @Nullable
+    default Set<String> getStringSet(String key, @Nullable Set<String> defValues) {
+        return defValues;
+    }
+
+    /**
+     * Retrieve an int value from the data store.
+     *
+     * @param key The name of the preference to retrieve.
+     * @param defValue Value to return if this preference does not exist.
+     * @see #putInt(String, int)
+     */
+    default int getInt(String key, int defValue) {
+        return defValue;
+    }
+
+    /**
+     * Retrieve a long value from the data store.
+     *
+     * @param key The name of the preference to retrieve.
+     * @param defValue Value to return if this preference does not exist.
+     * @see #putLong(String, long)
+     */
+    default long getLong(String key, long defValue) {
+        return defValue;
+    }
+
+    /**
+     * Retrieve a float value from the data store.
+     *
+     * @param key The name of the preference to retrieve.
+     * @param defValue Value to return if this preference does not exist.
+     * @see #putFloat(String, float)
+     */
+    default float getFloat(String key, float defValue) {
+        return defValue;
+    }
+
+    /**
+     * Retrieve a boolean value from the data store.
+     *
+     * @param key The name of the preference to retrieve.
+     * @param defValue Value to return if this preference does not exist.
+     * @see #getBoolean(String, boolean)
+     */
+    default boolean getBoolean(String key, boolean defValue) {
+        return defValue;
+    }
+}
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index 1a6b06f..a2f4db6 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -16,6 +16,7 @@
 
 package android.preference;
 
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.XmlRes;
 import android.app.Activity;
@@ -42,37 +43,39 @@
  * In most cases, clients should use
  * {@link PreferenceActivity#addPreferencesFromIntent} or
  * {@link PreferenceActivity#addPreferencesFromResource(int)}.
- * 
+ *
  * @see PreferenceActivity
  */
 public class PreferenceManager {
-    
+
     private static final String TAG = "PreferenceManager";
 
     /**
      * The Activity meta-data key for its XML preference hierarchy.
      */
     public static final String METADATA_KEY_PREFERENCES = "android.preference";
-    
+
     public static final String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
-    
+
     /**
      * @see #getActivity()
      */
+    @Nullable
     private Activity mActivity;
 
     /**
      * Fragment that owns this instance.
      */
+    @Nullable
     private PreferenceFragment mFragment;
 
     /**
      * The context to use. This should always be set.
-     * 
+     *
      * @see #mActivity
      */
     private Context mContext;
-    
+
     /**
      * The counter for unique IDs.
      */
@@ -86,26 +89,35 @@
     /**
      * Cached shared preferences.
      */
+    @Nullable
     private SharedPreferences mSharedPreferences;
-    
+
+    /**
+     * Data store to be used by the Preferences or null if {@link android.content.SharedPreferences}
+     * should be used.
+     */
+    @Nullable
+    private PreferenceDataStore mPreferenceDataStore;
+
     /**
      * If in no-commit mode, the shared editor to give out (which will be
      * committed when exiting no-commit mode).
      */
+    @Nullable
     private SharedPreferences.Editor mEditor;
-    
+
     /**
      * Blocks commits from happening on the shared editor. This is used when
      * inflating the hierarchy. Do not set this directly, use {@link #setNoCommit(boolean)}
      */
     private boolean mNoCommit;
-    
+
     /**
      * The SharedPreferences name that will be used for all {@link Preference}s
      * managed by this instance.
      */
     private String mSharedPreferencesName;
-    
+
     /**
      * The SharedPreferences mode that will be used for all {@link Preference}s
      * managed by this instance.
@@ -121,38 +133,43 @@
     /**
      * The {@link PreferenceScreen} at the root of the preference hierarchy.
      */
+    @Nullable
     private PreferenceScreen mPreferenceScreen;
 
     /**
      * List of activity result listeners.
      */
+    @Nullable
     private List<OnActivityResultListener> mActivityResultListeners;
 
     /**
      * List of activity stop listeners.
      */
+    @Nullable
     private List<OnActivityStopListener> mActivityStopListeners;
 
     /**
      * List of activity destroy listeners.
      */
+    @Nullable
     private List<OnActivityDestroyListener> mActivityDestroyListeners;
 
     /**
      * List of dialogs that should be dismissed when we receive onNewIntent in
      * our PreferenceActivity.
      */
+    @Nullable
     private List<DialogInterface> mPreferencesScreens;
-    
+
     private OnPreferenceTreeClickListener mOnPreferenceTreeClickListener;
-    
+
     /**
      * @hide
      */
     public PreferenceManager(Activity activity, int firstRequestCode) {
         mActivity = activity;
         mNextRequestCode = firstRequestCode;
-        
+
         init(activity);
     }
 
@@ -170,7 +187,7 @@
 
     private void init(Context context) {
         mContext = context;
-        
+
         setSharedPreferencesName(getDefaultSharedPreferencesName(context));
     }
 
@@ -184,14 +201,37 @@
     /**
      * Returns the owning preference fragment, if any.
      */
+    @Nullable
     PreferenceFragment getFragment() {
         return mFragment;
     }
 
     /**
+     * Sets a {@link PreferenceDataStore} to be used by all Preferences associated with this manager
+     * that don't have a custom {@link PreferenceDataStore} assigned. Also if the data store is set,
+     * the Preferences will no longer use {@link android.content.SharedPreferences}.
+     *
+     * @param dataStore The {@link PreferenceDataStore} to be used by this manager.
+     */
+    public void setPreferenceDataStore(PreferenceDataStore dataStore) {
+        mPreferenceDataStore = dataStore;
+    }
+
+    /**
+     * Returns the {@link PreferenceDataStore} associated with this manager or {@code null} if
+     * {@link android.content.SharedPreferences} are used instead.
+     *
+     * @return The {@link PreferenceDataStore} associated with this manager or {@code null} if none.
+     */
+    @Nullable
+    public PreferenceDataStore getPreferenceDataStore() {
+        return mPreferenceDataStore;
+    }
+
+    /**
      * Returns a list of {@link Activity} (indirectly) that match a given
      * {@link Intent}.
-     * 
+     *
      * @param queryIntent The Intent to match.
      * @return The list of {@link ResolveInfo} that point to the matched
      *         activities.
@@ -200,7 +240,7 @@
         return mContext.getPackageManager().queryIntentActivities(queryIntent,
                 PackageManager.GET_META_DATA);
     }
-    
+
     /**
      * Inflates a preference hierarchy from the preference hierarchies of
      * {@link Activity Activities} that match the given {@link Intent}. An
@@ -209,7 +249,7 @@
      * <p>
      * If a preference hierarchy is given, the new preference hierarchies will
      * be merged in.
-     * 
+     *
      * @param queryIntent The intent to match activities.
      * @param rootPreferences Optional existing hierarchy to merge the new
      *            hierarchies into.
@@ -232,7 +272,7 @@
             // can be re-used across contexts
             final String uniqueResId = activityInfo.packageName + ":"
                     + activityInfo.metaData.getInt(METADATA_KEY_PREFERENCES);
-            
+
             if (!inflatedRes.contains(uniqueResId)) {
                 inflatedRes.add(uniqueResId);
 
@@ -244,7 +284,7 @@
                         + Log.getStackTraceString(e));
                     continue;
                 }
-                
+
                 final PreferenceInflater inflater = new PreferenceInflater(context, this);
                 final XmlResourceParser parser = activityInfo.loadXmlMetaData(context
                         .getPackageManager(), METADATA_KEY_PREFERENCES);
@@ -255,14 +295,14 @@
         }
 
         rootPreferences.onAttachedToHierarchy(this);
-        
+
         return rootPreferences;
     }
 
     /**
      * Inflates a preference hierarchy from XML. If a preference hierarchy is
      * given, the new preference hierarchies will be merged in.
-     * 
+     *
      * @param context The context of the resource.
      * @param resId The resource ID of the XML to inflate.
      * @param rootPreferences Optional existing hierarchy to merge the new
@@ -285,16 +325,16 @@
 
         return rootPreferences;
     }
-    
+
     public PreferenceScreen createPreferenceScreen(Context context) {
         final PreferenceScreen preferenceScreen = new PreferenceScreen(context, null);
         preferenceScreen.onAttachedToHierarchy(this);
         return preferenceScreen;
     }
-    
+
     /**
      * Called by a preference to get a unique ID in its hierarchy.
-     * 
+     *
      * @return A unique ID.
      */
     long getNextId() {
@@ -302,11 +342,11 @@
             return mNextId++;
         }
     }
-    
+
     /**
      * Returns the current name of the SharedPreferences file that preferences managed by
      * this will use.
-     * 
+     *
      * @return The name that can be passed to {@link Context#getSharedPreferences(String, int)}.
      * @see Context#getSharedPreferences(String, int)
      */
@@ -317,7 +357,7 @@
     /**
      * Sets the name of the SharedPreferences file that preferences managed by this
      * will use.
-     * 
+     *
      * @param sharedPreferencesName The name of the SharedPreferences file.
      * @see Context#getSharedPreferences(String, int)
      */
@@ -329,7 +369,7 @@
     /**
      * Returns the current mode of the SharedPreferences file that preferences managed by
      * this will use.
-     * 
+     *
      * @return The mode that can be passed to {@link Context#getSharedPreferences(String, int)}.
      * @see Context#getSharedPreferences(String, int)
      */
@@ -340,7 +380,7 @@
     /**
      * Sets the mode of the SharedPreferences file that preferences managed by this
      * will use.
-     * 
+     *
      * @param sharedPreferencesMode The mode of the SharedPreferences file.
      * @see Context#getSharedPreferences(String, int)
      */
@@ -449,7 +489,7 @@
     /**
      * Gets a SharedPreferences instance that preferences managed by this will
      * use.
-     * 
+     *
      * @return A SharedPreferences instance pointing to the file that contains
      *         the values of preferences that are managed by this.
      */
@@ -471,14 +511,14 @@
             mSharedPreferences = storageContext.getSharedPreferences(mSharedPreferencesName,
                     mSharedPreferencesMode);
         }
-        
+
         return mSharedPreferences;
     }
-    
+
     /**
      * Gets a SharedPreferences instance that points to the default file that is
      * used by the preference framework in the given context.
-     * 
+     *
      * @param context The context of the preferences whose values are wanted.
      * @return A SharedPreferences instance that can be used to retrieve and
      *         listen to values of the preferences.
@@ -504,49 +544,51 @@
 
     /**
      * Returns the root of the preference hierarchy managed by this class.
-     *  
+     *
      * @return The {@link PreferenceScreen} object that is at the root of the hierarchy.
      */
+    @Nullable
     PreferenceScreen getPreferenceScreen() {
         return mPreferenceScreen;
     }
-    
+
     /**
      * Sets the root of the preference hierarchy.
-     * 
+     *
      * @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
-     * @return Whether the {@link PreferenceScreen} given is different than the previous. 
+     * @return Whether the {@link PreferenceScreen} given is different than the previous.
      */
     boolean setPreferences(PreferenceScreen preferenceScreen) {
         if (preferenceScreen != mPreferenceScreen) {
             mPreferenceScreen = preferenceScreen;
             return true;
         }
-        
+
         return false;
     }
-    
+
     /**
      * Finds a {@link Preference} based on its key.
-     * 
+     *
      * @param key The key of the preference to retrieve.
      * @return The {@link Preference} with the key, or null.
      * @see PreferenceGroup#findPreference(CharSequence)
      */
+    @Nullable
     public Preference findPreference(CharSequence key) {
         if (mPreferenceScreen == null) {
             return null;
         }
-        
+
         return mPreferenceScreen.findPreference(key);
     }
-    
+
     /**
      * Sets the default values from an XML preference file by reading the values defined
      * by each {@link Preference} item's {@code android:defaultValue} attribute. This should
      * be called by the application's main activity.
      * <p>
-     * 
+     *
      * @param context The context of the shared preferences.
      * @param resId The resource ID of the preference XML file.
      * @param readAgain Whether to re-read the default values.
@@ -563,12 +605,12 @@
      *            parameter set to true.
      */
     public static void setDefaultValues(Context context, @XmlRes int resId, boolean readAgain) {
-        
+
         // Use the default shared preferences name and mode
         setDefaultValues(context, getDefaultSharedPreferencesName(context),
                 getDefaultSharedPreferencesMode(), resId, readAgain);
     }
-    
+
     /**
      * Similar to {@link #setDefaultValues(Context, int, boolean)} but allows
      * the client to provide the filename and mode of the shared preferences
@@ -592,7 +634,7 @@
      *            {@link PreferenceManager#getDefaultSharedPreferences(Context)}
      *            and clear it followed by a call to this method with this
      *            parameter set to true.
-     * 
+     *
      * @see #setDefaultValues(Context, int, boolean)
      * @see #setSharedPreferencesName(String)
      * @see #setSharedPreferencesMode(int)
@@ -601,7 +643,7 @@
             int sharedPreferencesMode, int resId, boolean readAgain) {
         final SharedPreferences defaultValueSp = context.getSharedPreferences(
                 KEY_HAS_SET_DEFAULT_VALUES, Context.MODE_PRIVATE);
-        
+
         if (readAgain || !defaultValueSp.getBoolean(KEY_HAS_SET_DEFAULT_VALUES, false)) {
             final PreferenceManager pm = new PreferenceManager(context);
             pm.setSharedPreferencesName(sharedPreferencesName);
@@ -620,33 +662,33 @@
             }
         }
     }
-    
+
     /**
      * Returns an editor to use when modifying the shared preferences.
      * <p>
      * Do NOT commit unless {@link #shouldCommit()} returns true.
-     * 
+     *
      * @return An editor to use to write to shared preferences.
      * @see #shouldCommit()
      */
     SharedPreferences.Editor getEditor() {
-        
+
         if (mNoCommit) {
             if (mEditor == null) {
                 mEditor = getSharedPreferences().edit();
             }
-            
+
             return mEditor;
         } else {
             return getSharedPreferences().edit();
         }
     }
-    
+
     /**
      * Whether it is the client's responsibility to commit on the
      * {@link #getEditor()}. This will return false in cases where the writes
      * should be batched, for example when inflating preferences from XML.
-     * 
+     *
      * @return Whether the client should commit.
      */
     boolean shouldCommit() {
@@ -674,18 +716,19 @@
      * <p>
      * This will return null if this class was instantiated with a Context
      * instead of Activity. For example, when setting the default values.
-     * 
+     *
      * @return The activity that shows the preferences.
      * @see #mContext
      */
+    @Nullable
     Activity getActivity() {
         return mActivity;
     }
-    
+
     /**
      * Returns the context. This is preferred over {@link #getActivity()} when
      * possible.
-     * 
+     *
      * @return The context.
      */
     Context getContext() {
@@ -694,7 +737,7 @@
 
     /**
      * Registers a listener.
-     * 
+     *
      * @see OnActivityResultListener
      */
     void registerOnActivityResultListener(OnActivityResultListener listener) {
@@ -702,7 +745,7 @@
             if (mActivityResultListeners == null) {
                 mActivityResultListeners = new ArrayList<OnActivityResultListener>();
             }
-            
+
             if (!mActivityResultListeners.contains(listener)) {
                 mActivityResultListeners.add(listener);
             }
@@ -711,7 +754,7 @@
 
     /**
      * Unregisters a listener.
-     * 
+     *
      * @see OnActivityResultListener
      */
     void unregisterOnActivityResultListener(OnActivityResultListener listener) {
@@ -727,7 +770,7 @@
      */
     void dispatchActivityResult(int requestCode, int resultCode, Intent data) {
         List<OnActivityResultListener> list;
-        
+
         synchronized (this) {
             if (mActivityResultListeners == null) return;
             list = new ArrayList<OnActivityResultListener>(mActivityResultListeners);
@@ -743,7 +786,7 @@
 
     /**
      * Registers a listener.
-     * 
+     *
      * @see OnActivityStopListener
      * @hide
      */
@@ -752,16 +795,16 @@
             if (mActivityStopListeners == null) {
                 mActivityStopListeners = new ArrayList<OnActivityStopListener>();
             }
-            
+
             if (!mActivityStopListeners.contains(listener)) {
                 mActivityStopListeners.add(listener);
             }
         }
     }
-    
+
     /**
      * Unregisters a listener.
-     * 
+     *
      * @see OnActivityStopListener
      * @hide
      */
@@ -772,14 +815,14 @@
             }
         }
     }
-    
+
     /**
      * Called by the {@link PreferenceManager} to dispatch the activity stop
      * event.
      */
     void dispatchActivityStop() {
         List<OnActivityStopListener> list;
-        
+
         synchronized (this) {
             if (mActivityStopListeners == null) return;
             list = new ArrayList<OnActivityStopListener>(mActivityStopListeners);
@@ -793,7 +836,7 @@
 
     /**
      * Registers a listener.
-     * 
+     *
      * @see OnActivityDestroyListener
      */
     void registerOnActivityDestroyListener(OnActivityDestroyListener listener) {
@@ -807,10 +850,10 @@
             }
         }
     }
-    
+
     /**
      * Unregisters a listener.
-     * 
+     *
      * @see OnActivityDestroyListener
      */
     void unregisterOnActivityDestroyListener(OnActivityDestroyListener listener) {
@@ -820,14 +863,14 @@
             }
         }
     }
-    
+
     /**
      * Called by the {@link PreferenceManager} to dispatch the activity destroy
      * event.
      */
     void dispatchActivityDestroy() {
         List<OnActivityDestroyListener> list = null;
-        
+
         synchronized (this) {
             if (mActivityDestroyListeners != null) {
                 list = new ArrayList<OnActivityDestroyListener>(mActivityDestroyListeners);
@@ -844,11 +887,11 @@
         // Dismiss any PreferenceScreens still showing
         dismissAllScreens();
     }
-    
+
     /**
      * Returns a request code that is unique for the activity. Each subsequent
      * call to this method should return another unique request code.
-     * 
+     *
      * @return A unique request code that will never be used by anyone other
      *         than the caller of this method.
      */
@@ -857,32 +900,32 @@
             return mNextRequestCode++;
         }
     }
-    
+
     void addPreferencesScreen(DialogInterface screen) {
         synchronized (this) {
-            
+
             if (mPreferencesScreens == null) {
                 mPreferencesScreens = new ArrayList<DialogInterface>();
             }
-            
+
             mPreferencesScreens.add(screen);
         }
     }
-    
+
     void removePreferencesScreen(DialogInterface screen) {
         synchronized (this) {
-            
+
             if (mPreferencesScreens == null) {
                 return;
             }
-            
+
             mPreferencesScreens.remove(screen);
         }
     }
-    
+
     /**
      * Called by {@link PreferenceActivity} to dispatch the new Intent event.
-     * 
+     *
      * @param intent The new Intent.
      */
     void dispatchNewIntent(Intent intent) {
@@ -894,34 +937,35 @@
         ArrayList<DialogInterface> screensToDismiss;
 
         synchronized (this) {
-            
+
             if (mPreferencesScreens == null) {
                 return;
             }
-            
+
             screensToDismiss = new ArrayList<DialogInterface>(mPreferencesScreens);
             mPreferencesScreens.clear();
         }
-        
+
         for (int i = screensToDismiss.size() - 1; i >= 0; i--) {
             screensToDismiss.get(i).dismiss();
         }
     }
-    
+
     /**
      * Sets the callback to be invoked when a {@link Preference} in the
      * hierarchy rooted at this {@link PreferenceManager} is clicked.
-     * 
+     *
      * @param listener The callback to be invoked.
      */
     void setOnPreferenceTreeClickListener(OnPreferenceTreeClickListener listener) {
         mOnPreferenceTreeClickListener = listener;
     }
 
+    @Nullable
     OnPreferenceTreeClickListener getOnPreferenceTreeClickListener() {
         return mOnPreferenceTreeClickListener;
     }
-    
+
     /**
      * Interface definition for a callback to be invoked when a
      * {@link Preference} in the hierarchy rooted at this {@link PreferenceScreen} is
@@ -933,7 +977,7 @@
         /**
          * Called when a preference in the tree rooted at this
          * {@link PreferenceScreen} has been clicked.
-         * 
+         *
          * @param preferenceScreen The {@link PreferenceScreen} that the
          *        preference is located in.
          * @param preference The preference that was clicked.
@@ -947,22 +991,22 @@
      * receives an activity result.
      */
     public interface OnActivityResultListener {
-        
+
         /**
          * See Activity's onActivityResult.
-         * 
+         *
          * @return Whether the request code was handled (in which case
          *         subsequent listeners will not be called.
          */
         boolean onActivityResult(int requestCode, int resultCode, Intent data);
     }
-    
+
     /**
      * Interface definition for a class that will be called when the container's activity
      * is stopped.
      */
     public interface OnActivityStopListener {
-        
+
         /**
          * See Activity's onStop.
          */
@@ -974,7 +1018,7 @@
      * is destroyed.
      */
     public interface OnActivityDestroyListener {
-        
+
         /**
          * See Activity's onDestroy.
          */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 0946906..b5c7f7b 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7741,6 +7741,13 @@
        public static final String WIFI_SCAN_ALWAYS_AVAILABLE =
                 "wifi_scan_always_enabled";
 
+        /**
+         * Value to specify if Wi-Fi Wakeup feature is enabled.
+         * @hide
+         */
+        @SystemApi
+        public static final String WIFI_WAKEUP_ENABLED = "wifi_wakeup_enabled";
+
        /**
         * Settings to allow BLE scans to be enabled even when Bluetooth is turned off for
         * connectivity.
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 02ab30a..37674a6 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -78,9 +78,7 @@
  */
 public abstract class NotificationListenerService extends Service {
 
-    // TAG = "NotificationListenerService[MySubclass]"
-    private final String TAG = NotificationListenerService.class.getSimpleName()
-            + "[" + getClass().getSimpleName() + "]";
+    private final String TAG = getClass().getSimpleName();
 
     /**
      * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index dfb6b86..b0b2065 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -349,7 +349,8 @@
         if (mContext == null) {
             try {
                 ApplicationInfo ai = context.getPackageManager()
-                        .getApplicationInfo(pkg, PackageManager.GET_UNINSTALLED_PACKAGES);
+                        .getApplicationInfoAsUser(pkg, PackageManager.MATCH_UNINSTALLED_PACKAGES,
+                                getUserId());
                 mContext = context.createApplicationContext(ai,
                         Context.CONTEXT_RESTRICTED);
             } catch (PackageManager.NameNotFoundException e) {
diff --git a/core/java/android/service/persistentdata/PersistentDataBlockManager.java b/core/java/android/service/persistentdata/PersistentDataBlockManager.java
index 0f92ed0..cb021bc 100644
--- a/core/java/android/service/persistentdata/PersistentDataBlockManager.java
+++ b/core/java/android/service/persistentdata/PersistentDataBlockManager.java
@@ -68,6 +68,7 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface FlashLockState {}
 
+    /** @hide */
     public PersistentDataBlockManager(IPersistentDataBlockService service) {
         sService = service;
     }
@@ -79,6 +80,9 @@
      * Returns the number of bytes written or -1 on error. If the block is too big
      * to fit on the partition, returns -MAX_BLOCK_SIZE.
      *
+     * {@link #wipe} will block any further {@link #write} operation until reboot,
+     * in which case -1 will be returned.
+     *
      * @param data the data to write
      */
     public int write(byte[] data) {
@@ -129,6 +133,8 @@
     /**
      * Zeroes the previously written block in its entirety. Calling this method
      * will erase all data written to the persistent data partition.
+     * It will also prevent any further {@link #write} operation until reboot,
+     * in order to prevent a potential race condition. See b/30352311.
      */
     public void wipe() {
         try {
diff --git a/core/java/android/util/jar/StrictJarVerifier.java b/core/java/android/util/jar/StrictJarVerifier.java
index cb71ecc..debc170 100644
--- a/core/java/android/util/jar/StrictJarVerifier.java
+++ b/core/java/android/util/jar/StrictJarVerifier.java
@@ -17,7 +17,7 @@
 
 package android.util.jar;
 
-import java.io.ByteArrayInputStream;
+import android.util.apk.ApkSignatureSchemeV2Verifier;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
@@ -33,13 +33,9 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
-import java.util.Set;
 import java.util.StringTokenizer;
 import java.util.jar.Attributes;
 import java.util.jar.JarFile;
-import android.util.ArraySet;
-import android.util.apk.ApkSignatureSchemeV2Verifier;
-import libcore.io.Base64;
 import sun.security.jca.Providers;
 import sun.security.pkcs.PKCS7;
 import sun.security.pkcs.SignerInfo;
@@ -139,7 +135,7 @@
          */
         void verify() {
             byte[] d = digest.digest();
-            if (!MessageDigest.isEqual(d, Base64.decode(hash))) {
+            if (!verifyMessageDigest(d, hash)) {
                 throw invalidDigest(JarFile.MANIFEST_NAME, name, name);
             }
             verifiedEntries.put(name, certChains);
@@ -490,12 +486,22 @@
                 md.update(data, start, end - start);
             }
             byte[] b = md.digest();
-            byte[] hashBytes = hash.getBytes(StandardCharsets.ISO_8859_1);
-            return MessageDigest.isEqual(b, Base64.decode(hashBytes));
+            byte[] encodedHashBytes = hash.getBytes(StandardCharsets.ISO_8859_1);
+            return verifyMessageDigest(b, encodedHashBytes);
         }
         return ignorable;
     }
 
+    private static boolean verifyMessageDigest(byte[] expected, byte[] encodedActual) {
+        byte[] actual;
+        try {
+            actual = java.util.Base64.getDecoder().decode(encodedActual);
+        } catch (IllegalArgumentException e) {
+            return false;
+        }
+        return MessageDigest.isEqual(expected, actual);
+    }
+
     /**
      * Returns all of the {@link java.security.cert.Certificate} chains that
      * were used to verify the signature on the JAR entry called
diff --git a/core/java/android/view/GraphicBuffer.java b/core/java/android/view/GraphicBuffer.java
index 5f2a9cd..64611d0 100644
--- a/core/java/android/view/GraphicBuffer.java
+++ b/core/java/android/view/GraphicBuffer.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
@@ -264,6 +265,16 @@
         nWriteGraphicBufferToParcel(mNativeObject, dest);
     }
 
+    /**
+     * Create hardware bitmap backed by this GraphicBuffer.
+     *
+     * @return Bitmap or null if this GraphicBuffer has unsupported PixelFormat.
+     *         currently PIXEL_FORMAT_RGBA_8888 is the only supported format
+     */
+    public Bitmap createHardwareBitmap() {
+        return nCreateHardwareBitmap(mNativeObject);
+    }
+
     public static final Parcelable.Creator<GraphicBuffer> CREATOR =
             new Parcelable.Creator<GraphicBuffer>() {
         public GraphicBuffer createFromParcel(Parcel in) {
@@ -289,4 +300,5 @@
     private static native long nReadGraphicBufferFromParcel(Parcel in);
     private static native boolean nLockCanvas(long nativeObject, Canvas canvas, Rect dirty);
     private static native boolean nUnlockCanvasAndPost(long nativeObject, Canvas canvas);
+    private static native Bitmap nCreateHardwareBitmap(long nativeObject);
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 84d7548..f9a03c0 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4194,6 +4194,8 @@
         int endPadding = UNDEFINED_PADDING;
 
         int padding = -1;
+        int paddingHorizontal = -1;
+        int paddingVertical = -1;
 
         int viewFlagValues = 0;
         int viewFlagMasks = 0;
@@ -4240,6 +4242,16 @@
                     leftPaddingDefined = true;
                     rightPaddingDefined = true;
                     break;
+                case com.android.internal.R.styleable.View_paddingHorizontal:
+                    paddingHorizontal = a.getDimensionPixelSize(attr, -1);
+                    mUserPaddingLeftInitial = paddingHorizontal;
+                    mUserPaddingRightInitial = paddingHorizontal;
+                    leftPaddingDefined = true;
+                    rightPaddingDefined = true;
+                    break;
+                case com.android.internal.R.styleable.View_paddingVertical:
+                    paddingVertical = a.getDimensionPixelSize(attr, -1);
+                    break;
                  case com.android.internal.R.styleable.View_paddingLeft:
                     leftPadding = a.getDimensionPixelSize(attr, -1);
                     mUserPaddingLeftInitial = leftPadding;
@@ -4647,6 +4659,17 @@
             bottomPadding = padding;
             mUserPaddingLeftInitial = padding;
             mUserPaddingRightInitial = padding;
+        } else {
+            if (paddingHorizontal >= 0) {
+                leftPadding = paddingHorizontal;
+                rightPadding = paddingHorizontal;
+                mUserPaddingLeftInitial = paddingHorizontal;
+                mUserPaddingRightInitial = paddingHorizontal;
+            }
+            if (paddingVertical >= 0) {
+                topPadding = paddingVertical;
+                bottomPadding = paddingVertical;
+            }
         }
 
         if (isRtlCompatibilityMode()) {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index c0191ce..0f8200d 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -7357,34 +7357,48 @@
                 rightMargin= margin;
                 bottomMargin = margin;
             } else {
-                leftMargin = a.getDimensionPixelSize(
-                        R.styleable.ViewGroup_MarginLayout_layout_marginLeft,
-                        UNDEFINED_MARGIN);
-                if (leftMargin == UNDEFINED_MARGIN) {
-                    mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
-                    leftMargin = DEFAULT_MARGIN_RESOLVED;
-                }
-                rightMargin = a.getDimensionPixelSize(
-                        R.styleable.ViewGroup_MarginLayout_layout_marginRight,
-                        UNDEFINED_MARGIN);
-                if (rightMargin == UNDEFINED_MARGIN) {
-                    mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
-                    rightMargin = DEFAULT_MARGIN_RESOLVED;
+                int horizontalMargin = a.getDimensionPixelSize(
+                        R.styleable.ViewGroup_MarginLayout_layout_marginHorizontal, -1);
+                int verticalMargin = a.getDimensionPixelSize(
+                        R.styleable.ViewGroup_MarginLayout_layout_marginVertical, -1);
+
+                if (horizontalMargin >= 0) {
+                    leftMargin = horizontalMargin;
+                    rightMargin = horizontalMargin;
+                } else {
+                    leftMargin = a.getDimensionPixelSize(
+                            R.styleable.ViewGroup_MarginLayout_layout_marginLeft,
+                            UNDEFINED_MARGIN);
+                    if (leftMargin == UNDEFINED_MARGIN) {
+                        mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
+                        leftMargin = DEFAULT_MARGIN_RESOLVED;
+                    }
+                    rightMargin = a.getDimensionPixelSize(
+                            R.styleable.ViewGroup_MarginLayout_layout_marginRight,
+                            UNDEFINED_MARGIN);
+                    if (rightMargin == UNDEFINED_MARGIN) {
+                        mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
+                        rightMargin = DEFAULT_MARGIN_RESOLVED;
+                    }
+                    startMargin = a.getDimensionPixelSize(
+                            R.styleable.ViewGroup_MarginLayout_layout_marginStart,
+                            DEFAULT_MARGIN_RELATIVE);
+                    endMargin = a.getDimensionPixelSize(
+                            R.styleable.ViewGroup_MarginLayout_layout_marginEnd,
+                            DEFAULT_MARGIN_RELATIVE);
                 }
 
-                topMargin = a.getDimensionPixelSize(
-                        R.styleable.ViewGroup_MarginLayout_layout_marginTop,
-                        DEFAULT_MARGIN_RESOLVED);
-                bottomMargin = a.getDimensionPixelSize(
-                        R.styleable.ViewGroup_MarginLayout_layout_marginBottom,
-                        DEFAULT_MARGIN_RESOLVED);
-
-                startMargin = a.getDimensionPixelSize(
-                        R.styleable.ViewGroup_MarginLayout_layout_marginStart,
-                        DEFAULT_MARGIN_RELATIVE);
-                endMargin = a.getDimensionPixelSize(
-                        R.styleable.ViewGroup_MarginLayout_layout_marginEnd,
-                        DEFAULT_MARGIN_RELATIVE);
+                if (verticalMargin >= 0) {
+                    topMargin = verticalMargin;
+                    bottomMargin = verticalMargin;
+                } else {
+                    topMargin = a.getDimensionPixelSize(
+                            R.styleable.ViewGroup_MarginLayout_layout_marginTop,
+                            DEFAULT_MARGIN_RESOLVED);
+                    bottomMargin = a.getDimensionPixelSize(
+                            R.styleable.ViewGroup_MarginLayout_layout_marginBottom,
+                            DEFAULT_MARGIN_RESOLVED);
+                }
 
                 if (isMarginRelative()) {
                    mMarginFlags |= NEED_RESOLUTION_MASK;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 2c13831..e04c613 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -301,6 +301,7 @@
     private boolean mDestroyed;
 
     private boolean mOverlayWithDecorCaptionEnabled = false;
+    private boolean mCloseOnSwipeEnabled = false;
 
     // The current window attributes.
     private final WindowManager.LayoutParams mWindowAttributes =
@@ -2209,4 +2210,21 @@
      * @hide
      */
     public abstract void reportActivityRelaunched();
+
+    /**
+     * Called to set flag to check if the close on swipe is enabled. This will only function if
+     * FEATURE_SWIPE_TO_DISMISS has been set.
+     * @hide
+     */
+    public void setCloseOnSwipeEnabled(boolean closeOnSwipeEnabled) {
+        mCloseOnSwipeEnabled = closeOnSwipeEnabled;
+    }
+
+    /**
+     * @return {@code true} if the close on swipe is enabled.
+     * @hide
+     */
+    public boolean isCloseOnSwipeEnabled() {
+        return mCloseOnSwipeEnabled;
+    }
 }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index b8408dd..aa7631d 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -922,8 +922,11 @@
          * unlock credential) than the user will still need to confirm it before
          * seeing this window, unless {@link #FLAG_SHOW_WHEN_LOCKED} has
          * also been set.
-         * @see KeyguardManager#dismissKeyguard
+         * @deprecated Use {@link #FLAG_SHOW_WHEN_LOCKED} or {@link KeyguardManager#dismissKeyguard}
+         * instead. The Keyguard should never be dismissed automatically repeatedly as it also
+         * guards against unintentional touches.
          */
+        @Deprecated
         public static final int FLAG_DISMISS_KEYGUARD = 0x00400000;
 
         /** Window flag: when set the window will accept for touch events
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 3171019..2f55fc9 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -482,6 +482,16 @@
          */
         public void switchInputMethod(boolean forwardDirection);
 
+        /**
+         * Returns the visibility of the current input method window (false if there is none).
+         */
+        public boolean isInputMethodWindowVisible();
+
+        /**
+         * Hides the current input method, if visible.
+         */
+        public void hideCurrentInputMethod();
+
         public void shutdown(boolean confirm);
         public void reboot(boolean confirm);
         public void rebootSafeMode(boolean confirm);
diff --git a/core/java/android/view/animation/PathInterpolator.java b/core/java/android/view/animation/PathInterpolator.java
index eec5555..924437a 100644
--- a/core/java/android/view/animation/PathInterpolator.java
+++ b/core/java/android/view/animation/PathInterpolator.java
@@ -25,6 +25,9 @@
 import android.view.InflateException;
 
 import com.android.internal.R;
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
 
 /**
  * An interpolator that can traverse a Path that extends from <code>Point</code>
@@ -42,7 +45,8 @@
  *     path.lineTo(1f, 1f);
  * </pre></blockquote></p>
  */
-public class PathInterpolator extends BaseInterpolator {
+@HasNativeInterpolator
+public class PathInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
 
     // This governs how accurate the approximation of the Path is.
     private static final float PRECISION = 0.002f;
@@ -229,4 +233,11 @@
         float endY = mY[endIndex];
         return startY + (fraction * (endY - startY));
     }
+
+    /** @hide **/
+    @Override
+    public long createNativeInterpolator() {
+        return NativeInterpolatorFactoryHelper.createPathInterpolator(mX, mY);
+    }
+
 }
diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java
index c206974..e0d589a 100644
--- a/core/java/android/webkit/WebViewZygote.java
+++ b/core/java/android/webkit/WebViewZygote.java
@@ -53,6 +53,10 @@
         return sPackage.packageName;
     }
 
+    public static boolean isMultiprocessEnabled() {
+        return sMultiprocessEnabled && sPackage != null;
+    }
+
     public static void setMultiprocessEnabled(boolean enabled) {
         sMultiprocessEnabled = enabled;
 
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index d5a933c..8cedb17 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2168,7 +2168,6 @@
         }
 
         layoutChildren();
-        mInLayout = false;
 
         mOverscrollMax = (b - t) / OVERSCROLL_LIMIT_DIVISOR;
 
@@ -2176,6 +2175,7 @@
         if (mFastScroll != null) {
             mFastScroll.onItemCountChanged(getChildCount(), mItemCount);
         }
+        mInLayout = false;
     }
 
     /**
@@ -2705,6 +2705,9 @@
      * fail to relayout them properly to accommodate for new bounds.
      */
     void handleBoundsChange() {
+        if (mInLayout) {
+            return;
+        }
         final int childCount = getChildCount();
         if (childCount > 0) {
             mDataChanged = true;
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index a3134b3b..98d87d3 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -355,7 +355,7 @@
         ApplicationInfo existingInfo = null;
         try {
             existingInfo = context.getPackageManager().getApplicationInfo(packageName,
-                    PackageManager.GET_UNINSTALLED_PACKAGES);
+                    PackageManager.MATCH_ANY_USER);
         } catch (NameNotFoundException ignored) {
         }
 
@@ -445,7 +445,7 @@
         ApplicationInfo existingInfo = null;
         try {
             existingInfo = context.getPackageManager().getApplicationInfo(packageName,
-                    PackageManager.GET_UNINSTALLED_PACKAGES);
+                    PackageManager.MATCH_ANY_USER);
         } catch (NameNotFoundException ignored) {
         }
 
diff --git a/core/java/com/android/internal/os/FuseAppLoop.java b/core/java/com/android/internal/os/FuseAppLoop.java
new file mode 100644
index 0000000..34253ce
--- /dev/null
+++ b/core/java/com/android/internal/os/FuseAppLoop.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.internal.os;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.IProxyFileDescriptorCallback;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.OsConstants;
+import android.util.Log;
+import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+public class FuseAppLoop {
+    private static final String TAG = "FuseAppLoop";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    public static final int ROOT_INODE = 1;
+    private static final int MIN_INODE = 2;
+
+    private final Object mLock = new Object();
+    private final File mParent;
+
+    @GuardedBy("mLock")
+    private final SparseArray<CallbackEntry> mCallbackMap = new SparseArray<>();
+
+    @GuardedBy("mLock")
+    private boolean mActive = true;
+
+    /**
+     * Sequential number can be used as file name and inode in AppFuse.
+     * 0 is regarded as an error, 1 is mount point. So we start the number from 2.
+     */
+    @GuardedBy("mLock")
+    private int mNextInode = MIN_INODE;
+
+    private FuseAppLoop(@NonNull File parent) {
+        mParent = parent;
+    }
+
+    public static @NonNull FuseAppLoop open(
+            @NonNull File parent, @NonNull ParcelFileDescriptor fd) {
+        Preconditions.checkNotNull(parent);
+        Preconditions.checkNotNull(fd);
+        final FuseAppLoop bridge = new FuseAppLoop(parent);
+        final int rawFd = fd.detachFd();
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                bridge.native_start_loop(rawFd);
+            }
+        }, TAG).start();
+        return bridge;
+    }
+
+    public @NonNull ParcelFileDescriptor openFile(int mode, IProxyFileDescriptorCallback callback)
+            throws UnmountedException, IOException {
+        int id;
+        synchronized (mLock) {
+            if (!mActive) {
+                throw new UnmountedException();
+            }
+            if (mCallbackMap.size() >= Integer.MAX_VALUE - MIN_INODE) {
+                throw new IOException("Too many opened files.");
+            }
+            while (true) {
+                id = mNextInode;
+                mNextInode++;
+                if (mNextInode < 0) {
+                    mNextInode = MIN_INODE;
+                }
+                if (mCallbackMap.get(id) == null) {
+                    break;
+                }
+            }
+
+            // Register callback after we succeed to create pfd.
+            mCallbackMap.put(id, new CallbackEntry(callback));
+        }
+        try {
+            return ParcelFileDescriptor.open(new File(mParent, String.valueOf(id)), mode);
+        } catch (FileNotFoundException error) {
+            synchronized (mLock) {
+                mCallbackMap.remove(id);
+            }
+            throw error;
+        }
+    }
+
+    public @Nullable File getMountPoint() {
+        synchronized (mLock) {
+            return mActive ? mParent : null;
+        }
+    }
+
+    private CallbackEntry getCallbackEntryOrThrowLocked(long inode) throws ErrnoException {
+        final CallbackEntry entry = mCallbackMap.get(checkInode(inode));
+        if (entry != null) {
+            return entry;
+        } else {
+            throw new ErrnoException("getCallbackEntry", OsConstants.ENOENT);
+        }
+    }
+
+    // Called by JNI.
+    @SuppressWarnings("unused")
+    private long onGetSize(long inode) {
+        synchronized(mLock) {
+            try {
+                return getCallbackEntryOrThrowLocked(inode).callback.onGetSize();
+            } catch (ErrnoException exp) {
+                return -exp.errno;
+            }
+        }
+    }
+
+    // Called by JNI.
+    @SuppressWarnings("unused")
+    private int onOpen(long inode) {
+        synchronized(mLock) {
+            try {
+                final CallbackEntry entry = getCallbackEntryOrThrowLocked(inode);
+                if (entry.opened) {
+                    throw new ErrnoException("onOpen", OsConstants.EMFILE);
+                }
+                entry.opened = true;
+                // Use inode as file handle. It's OK because AppFuse does not allow to open the same
+                // file twice.
+                return (int) inode;
+            } catch (ErrnoException exp) {
+                return -exp.errno;
+            }
+        }
+    }
+
+    // Called by JNI.
+    @SuppressWarnings("unused")
+    private int onFsync(long inode) {
+        synchronized(mLock) {
+            try {
+                getCallbackEntryOrThrowLocked(inode).callback.onFsync();
+                return 0;
+            } catch (ErrnoException exp) {
+                return -exp.errno;
+            }
+        }
+    }
+
+    // Called by JNI.
+    @SuppressWarnings("unused")
+    private int onRelease(long inode) {
+        synchronized(mLock) {
+            mCallbackMap.remove(checkInode(inode));
+            if (mCallbackMap.size() == 0) {
+                mActive = false;
+                return -1;
+            }
+            return 0;
+        }
+    }
+
+    // Called by JNI.
+    @SuppressWarnings("unused")
+    private int onRead(long inode, long offset, int size, byte[] bytes) {
+        synchronized(mLock) {
+            try {
+                return getCallbackEntryOrThrowLocked(inode).callback.onRead(offset, size, bytes);
+            } catch (ErrnoException exp) {
+                return -exp.errno;
+            }
+        }
+    }
+
+    // Called by JNI.
+    @SuppressWarnings("unused")
+    private int onWrite(long inode, long offset, int size, byte[] bytes) {
+        synchronized(mLock) {
+            try {
+                return getCallbackEntryOrThrowLocked(inode).callback.onWrite(offset, size, bytes);
+            } catch (ErrnoException exp) {
+                return -exp.errno;
+            }
+        }
+    }
+
+    native boolean native_start_loop(int fd);
+
+    private static int checkInode(long inode) {
+        Preconditions.checkArgumentInRange(inode, MIN_INODE, Integer.MAX_VALUE, "checkInode");
+        return (int) inode;
+    }
+
+    public static class UnmountedException extends Exception {}
+
+    private static class CallbackEntry {
+        final IProxyFileDescriptorCallback callback;
+        boolean opened;
+        CallbackEntry(IProxyFileDescriptorCallback callback) {
+            Preconditions.checkNotNull(callback);
+            this.callback = callback;
+        }
+    }
+}
diff --git a/core/java/com/android/internal/os/RoSystemProperties.java b/core/java/com/android/internal/os/RoSystemProperties.java
index 7591488..1d26df0 100644
--- a/core/java/com/android/internal/os/RoSystemProperties.java
+++ b/core/java/com/android/internal/os/RoSystemProperties.java
@@ -27,8 +27,8 @@
             SystemProperties.getInt("ro.debuggable", 0) == 1;
     public static final int FACTORYTEST =
             SystemProperties.getInt("ro.factorytest", 0);
-    public static final boolean CONTROL_PRIVAPP_PERMISSIONS =
-            SystemProperties.getBoolean("ro.control_privapp_permissions", false);
+    public static final String CONTROL_PRIVAPP_PERMISSIONS =
+            SystemProperties.get("ro.control_privapp_permissions");
 
     // ------ ro.config.* -------- //
     public static final boolean CONFIG_LOW_RAM =
@@ -50,4 +50,12 @@
             "file".equalsIgnoreCase(CRYPTO_TYPE);
     public static final boolean CRYPTO_BLOCK_ENCRYPTED =
             "block".equalsIgnoreCase(CRYPTO_TYPE);
+
+    public static final boolean CONTROL_PRIVAPP_PERMISSIONS_LOG =
+            "log".equalsIgnoreCase(CONTROL_PRIVAPP_PERMISSIONS);
+    public static final boolean CONTROL_PRIVAPP_PERMISSIONS_ENFORCE =
+            "enforce".equalsIgnoreCase(CONTROL_PRIVAPP_PERMISSIONS);
+    public static final boolean CONTROL_PRIVAPP_PERMISSIONS_DISABLE =
+            !CONTROL_PRIVAPP_PERMISSIONS_LOG && !CONTROL_PRIVAPP_PERMISSIONS_ENFORCE;
+
 }
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index cdd267e..32876ac 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -572,7 +572,7 @@
         String args[] = {
             "--setuid=1000",
             "--setgid=1000",
-            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007,3009,3010",
+            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010",
             "--capabilities=" + capabilities + "," + capabilities,
             "--nice-name=system_server",
             "--runtime-args",
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 2a004cfb..8c682b9 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -2502,6 +2502,7 @@
         // System.out.println("Features: 0x" + Integer.toHexString(features));
         if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
             layoutResource = R.layout.screen_swipe_dismiss;
+            setCloseOnSwipeEnabled(true);
         } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
             if (mIsFloating) {
                 TypedValue res = new TypedValue();
@@ -2573,7 +2574,7 @@
         }
 
         if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
-            registerSwipeCallbacks();
+            registerSwipeCallbacks(contentParent);
         }
 
         // Remaining setup -- of background and title -- that only applies
@@ -2987,9 +2988,12 @@
         return (mRightIconView = (ImageView)findViewById(R.id.right_icon));
     }
 
-    private void registerSwipeCallbacks() {
-        SwipeDismissLayout swipeDismiss =
-                (SwipeDismissLayout) findViewById(R.id.content);
+    private void registerSwipeCallbacks(ViewGroup contentParent) {
+        if (!(contentParent instanceof SwipeDismissLayout)) {
+            Log.w(TAG, "contentParent is not a SwipeDismissLayout: " + contentParent);
+            return;
+        }
+        SwipeDismissLayout swipeDismiss = (SwipeDismissLayout) contentParent;
         swipeDismiss.setOnDismissedListener(new SwipeDismissLayout.OnDismissedListener() {
             @Override
             public void onDismissed(SwipeDismissLayout layout) {
@@ -3028,6 +3032,16 @@
                 });
     }
 
+    /** @hide */
+    @Override
+    public void setCloseOnSwipeEnabled(boolean closeOnSwipeEnabled) {
+        if (hasFeature(Window.FEATURE_SWIPE_TO_DISMISS) // swipe-to-dismiss feature is requested
+                && mContentParent instanceof SwipeDismissLayout) { // check casting mContentParent
+            ((SwipeDismissLayout) mContentParent).setDismissable(closeOnSwipeEnabled);
+        }
+        super.setCloseOnSwipeEnabled(closeOnSwipeEnabled);
+    }
+
     /**
      * Helper method for calling the {@link Callback#onPanelClosed(int, Menu)}
      * callback. This method will grab whatever extra state is needed for the
diff --git a/core/java/com/android/internal/view/animation/NativeInterpolatorFactoryHelper.java b/core/java/com/android/internal/view/animation/NativeInterpolatorFactoryHelper.java
index 7cd75f3..ebeec40 100644
--- a/core/java/com/android/internal/view/animation/NativeInterpolatorFactoryHelper.java
+++ b/core/java/com/android/internal/view/animation/NativeInterpolatorFactoryHelper.java
@@ -32,5 +32,6 @@
     public static native long createDecelerateInterpolator(float factor);
     public static native long createLinearInterpolator();
     public static native long createOvershootInterpolator(float tension);
+    public static native long createPathInterpolator(float[] x, float[] y);
     public static native long createLutInterpolator(float[] values);
 }
diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java
index d88f479..31e67bd 100644
--- a/core/java/com/android/internal/widget/SwipeDismissLayout.java
+++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java
@@ -110,6 +110,8 @@
 
     private float mLastX;
 
+    private boolean mDismissable = true;
+
     public SwipeDismissLayout(Context context) {
         super(context);
         init(context);
@@ -166,6 +168,10 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (!mDismissable) {
+            return super.onInterceptTouchEvent(ev);
+        }
+
         // offset because the view is translated during swipe
         ev.offsetLocation(mTranslationX, 0);
 
@@ -225,7 +231,7 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
-        if (mVelocityTracker == null) {
+        if (mVelocityTracker == null || !mDismissable) {
             return super.onTouchEvent(ev);
         }
         // offset because the view is translated during swipe
@@ -363,4 +369,13 @@
 
         return checkV && v.canScrollHorizontally((int) -dx);
     }
+
+    public void setDismissable(boolean dismissable) {
+        if (!dismissable && mDismissable) {
+            cancel();
+            resetMembers();
+        }
+
+        mDismissable = dismissable;
+    }
 }
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index a4e9576..77934fe 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -183,6 +183,7 @@
     android_content_res_Configuration.cpp \
     android_animation_PropertyValuesHolder.cpp \
     com_android_internal_net_NetworkStatsFactory.cpp \
+    com_android_internal_os_FuseAppLoop.cpp \
     com_android_internal_os_PathClassLoaderFactory.cpp \
     com_android_internal_os_Zygote.cpp \
     com_android_internal_util_VirtualRefBasePtr.cpp \
@@ -201,6 +202,7 @@
     $(TOP)/frameworks/base/media/jni \
     $(TOP)/system/core/base/include \
     $(TOP)/system/core/include \
+    $(TOP)/system/core/libappfuse/include \
     $(TOP)/system/media/camera/include \
     $(TOP)/system/netd/include \
     external/giflib \
@@ -215,7 +217,6 @@
     external/skia/src/images \
     external/sqlite/dist \
     external/sqlite/android \
-    external/expat/lib \
     external/tremor/Tremor \
     external/harfbuzz_ng/src \
     libcore/include \
@@ -230,18 +231,16 @@
 LOCAL_SHARED_LIBRARIES := \
     libmemtrack \
     libandroidfw \
+    libappfuse \
     libbase \
-    libexpat \
     libnativehelper \
     liblog \
     libcutils \
     libutils \
     libbinder \
-    libnetutils \
     libui \
     libgui \
     libinput \
-    libinputflinger \
     libcamera_client \
     libcamera_metadata \
     libskia \
@@ -254,18 +253,13 @@
     libhardware \
     libhardware_legacy \
     libselinux \
-    libsonivox \
-    libcrypto \
-    libssl \
     libicuuc \
-    libicui18n \
     libmedia \
     libaudioclient \
     libjpeg \
     libusbhost \
     libharfbuzz_ng \
     libz \
-    libaudioutils \
     libpdfium \
     libimg_utils \
     libnetd_client \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index cdaa4dc..1f810ac 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -201,6 +201,7 @@
 extern int register_android_animation_PropertyValuesHolder(JNIEnv *env);
 extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
 extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env);
+extern int register_com_android_internal_os_FuseAppLoop(JNIEnv* env);
 extern int register_com_android_internal_os_PathClassLoaderFactory(JNIEnv* env);
 extern int register_com_android_internal_os_Zygote(JNIEnv *env);
 extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
@@ -1419,7 +1420,7 @@
     REG_JNI(register_android_animation_PropertyValuesHolder),
     REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
     REG_JNI(register_com_android_internal_net_NetworkStatsFactory),
-
+    REG_JNI(register_com_android_internal_os_FuseAppLoop),
 };
 
 /*
diff --git a/core/jni/android_opengl_GLES20.cpp b/core/jni/android_opengl_GLES20.cpp
index ac3bf7a..b5c0b64 100644
--- a/core/jni/android_opengl_GLES20.cpp
+++ b/core/jni/android_opengl_GLES20.cpp
@@ -3084,15 +3084,16 @@
     GLint infoLen = 0;
     glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
     if (!infoLen) {
-        return _env->NewStringUTF("");
+        infoLen = 512;
     }
     char* buf = (char*) malloc(infoLen);
     if (buf == NULL) {
         jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory");
         return NULL;
     }
-    glGetShaderInfoLog(shader, infoLen, NULL, buf);
-    jstring result = _env->NewStringUTF(buf);
+    GLsizei outLen = 0;
+    glGetShaderInfoLog(shader, infoLen, &outLen, buf);
+    jstring result = _env->NewStringUTF(outLen == 0 ? "" : buf);
     free(buf);
     return result;
 }
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index 10090a1..23a988a 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -25,6 +25,8 @@
 
 #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_runtime/AndroidRuntime.h>
 #include <hidl/ServiceManagement.h>
 #include <hidl/Status.h>
@@ -239,11 +241,11 @@
     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);
     bool ok = hardware::defaultServiceManager()->add(
                 interfaceChain,
                 serviceName,
-                binder);
+                base);
 
     env->ReleaseStringUTFChars(serviceNameObj, serviceName);
     serviceName = NULL;
@@ -289,8 +291,10 @@
     hardware::defaultServiceManager()->get(
             ifaceName,
             serviceName,
-            [&service](sp<hardware::IBinder> out) {
-                service = out;
+            [&service](sp<hidl::base::V1_0::IBase> out) {
+                service = hardware::toBinder<
+                        hidl::base::V1_0::IBase, hidl::base::V1_0::IHwBase
+                    >(out);
             });
 
     env->ReleaseStringUTFChars(ifaceNameObj, ifaceName);
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index d70fbb9..d382f24 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -1179,67 +1179,17 @@
     return result ? JNI_TRUE : JNI_FALSE;
 }
 
-static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
-                                                        jlong themeToken,
-                                                        jint defStyleAttr,
-                                                        jint defStyleRes,
-                                                        jlong xmlParserToken,
-                                                        jintArray attrs,
-                                                        jintArray outValues,
-                                                        jintArray outIndices)
-{
-    if (themeToken == 0) {
-        jniThrowNullPointerException(env, "theme token");
-        return JNI_FALSE;
-    }
-    if (attrs == NULL) {
-        jniThrowNullPointerException(env, "attrs");
-        return JNI_FALSE;
-    }
-    if (outValues == NULL) {
-        jniThrowNullPointerException(env, "out values");
-        return JNI_FALSE;
-    }
-
-    const jsize NI = env->GetArrayLength(attrs);
-    const jsize NV = env->GetArrayLength(outValues);
-    if (NV < (NI*STYLE_NUM_ENTRIES)) {
-        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
-        return JNI_FALSE;
-    }
-
-    jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
-    if (src == NULL) {
-        return JNI_FALSE;
-    }
-
-    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
-    if (baseDest == NULL) {
-        env->ReleasePrimitiveArrayCritical(attrs, src, 0);
-        return JNI_FALSE;
-    }
-
-    jint* indices = NULL;
-    if (outIndices != NULL) {
-        if (env->GetArrayLength(outIndices) > NI) {
-            indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
-        }
-    }
-
+static void android_content_AssetManager_applyStyle(JNIEnv* env, jobject, jlong themeToken,
+        jint defStyleAttr, jint defStyleRes, jlong xmlParserToken, jintArray attrsObj, jint length,
+        jlong outValuesAddress, jlong outIndicesAddress) {
+    jint* attrs = env->GetIntArrayElements(attrsObj, 0);
     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
     ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
-    bool result = ApplyStyle(theme, xmlParser,
-                             defStyleAttr, defStyleRes,
-                             (uint32_t*) src, NI,
-                             (uint32_t*) baseDest,
-                             (uint32_t*) indices);
-
-    if (indices != NULL) {
-        env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
-    }
-    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
-    env->ReleasePrimitiveArrayCritical(attrs, src, 0);
-    return result ? JNI_TRUE : JNI_FALSE;
+    uint32_t* outValues = reinterpret_cast<uint32_t*>(static_cast<uintptr_t>(outValuesAddress));
+    uint32_t* outIndices = reinterpret_cast<uint32_t*>(static_cast<uintptr_t>(outIndicesAddress));
+    ApplyStyle(theme, xmlParser, defStyleAttr, defStyleRes,
+            reinterpret_cast<const uint32_t*>(attrs), length, outValues, outIndices);
+    env->ReleaseIntArrayElements(attrsObj, attrs, JNI_ABORT);
 }
 
 static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
@@ -1795,7 +1745,7 @@
     { "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V",
         (void*) android_content_AssetManager_dumpTheme },
     // @FastNative
-    { "applyStyle","(JIIJ[I[I[I)Z",
+    { "applyStyle","(JIIJ[IIJJ)V",
         (void*) android_content_AssetManager_applyStyle },
     // @FastNative
     { "resolveAttrs","(JII[I[I[I[I)Z",
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 173afd8..3219d59 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -16,16 +16,14 @@
 
 #include <fcntl.h>
 
+#include <log/log_event_list.h>
+
 #include "JNIHelp.h"
 #include "core_jni_helpers.h"
 #include "jni.h"
-#include <log/logger.h>
 
 #define UNUSED  __attribute__((__unused__))
 
-// The size of the tag number comes out of the payload size.
-#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
-
 namespace android {
 
 static jclass gCollectionClass;
@@ -53,7 +51,9 @@
                                                      jobject clazz UNUSED,
                                                      jint tag, jint value)
 {
-    return android_btWriteLog(tag, EVENT_TYPE_INT, &value, sizeof(value));
+    android_log_event_list ctx(tag);
+    ctx << (int32_t)value;
+    return ctx.write();
 }
 
 /*
@@ -64,7 +64,9 @@
                                                   jobject clazz UNUSED,
                                                   jint tag, jlong value)
 {
-    return android_btWriteLog(tag, EVENT_TYPE_LONG, &value, sizeof(value));
+    android_log_event_list ctx(tag);
+    ctx << (int64_t)value;
+    return ctx.write();
 }
 
 /*
@@ -75,7 +77,9 @@
                                                   jobject clazz UNUSED,
                                                   jint tag, jfloat value)
 {
-    return android_btWriteLog(tag, EVENT_TYPE_FLOAT, &value, sizeof(value));
+    android_log_event_list ctx(tag);
+    ctx << (float)value;
+    return ctx.write();
 }
 
 /*
@@ -85,22 +89,17 @@
 static jint android_util_EventLog_writeEvent_String(JNIEnv* env,
                                                     jobject clazz UNUSED,
                                                     jint tag, jstring value) {
-    uint8_t buf[MAX_EVENT_PAYLOAD];
-
+    android_log_event_list ctx(tag);
     // Don't throw NPE -- I feel like it's sort of mean for a logging function
     // to be all crashy if you pass in NULL -- but make the NULL value explicit.
-    const char *str = value != NULL ? env->GetStringUTFChars(value, NULL) : "NULL";
-    uint32_t len = strlen(str);
-    size_t max = sizeof(buf) - sizeof(len) - 2;  // Type byte, final newline
-    if (len > max) len = max;
-
-    buf[0] = EVENT_TYPE_STRING;
-    memcpy(&buf[1], &len, sizeof(len));
-    memcpy(&buf[1 + sizeof(len)], str, len);
-    buf[1 + sizeof(len) + len] = '\n';
-
-    if (value != NULL) env->ReleaseStringUTFChars(value, str);
-    return android_bWriteLog(tag, buf, 2 + sizeof(len) + len);
+    if (value != NULL) {
+        const char *str = env->GetStringUTFChars(value, NULL);
+        ctx << str;
+        env->ReleaseStringUTFChars(value, str);
+    } else {
+        ctx << "NULL";
+    }
+    return ctx.write();
 }
 
 /*
@@ -109,45 +108,29 @@
  */
 static jint android_util_EventLog_writeEvent_Array(JNIEnv* env, jobject clazz,
                                                    jint tag, jobjectArray value) {
-    if (value == NULL) {
-        return android_util_EventLog_writeEvent_String(env, clazz, tag, NULL);
-    }
+    android_log_event_list ctx(tag);
 
-    uint8_t buf[MAX_EVENT_PAYLOAD];
-    const size_t max = sizeof(buf) - 1;  // leave room for final newline
-    size_t pos = 2;  // Save room for type tag & array count
+    if (value == NULL) {
+        ctx << "[NULL]";
+        return ctx.write();
+    }
 
     jsize copied = 0, num = env->GetArrayLength(value);
     for (; copied < num && copied < 255; ++copied) {
+        if (ctx.status()) break;
         jobject item = env->GetObjectArrayElement(value, copied);
-        if (item == NULL || env->IsInstanceOf(item, gStringClass)) {
-            if (pos + 1 + sizeof(jint) > max) break;
-            const char *str = item != NULL ? env->GetStringUTFChars((jstring) item, NULL) : "NULL";
-            jint len = strlen(str);
-            if (pos + 1 + sizeof(len) + len > max) len = max - pos - 1 - sizeof(len);
-            buf[pos++] = EVENT_TYPE_STRING;
-            memcpy(&buf[pos], &len, sizeof(len));
-            memcpy(&buf[pos + sizeof(len)], str, len);
-            pos += sizeof(len) + len;
-            if (item != NULL) env->ReleaseStringUTFChars((jstring) item, str);
+        if (item == NULL) {
+            ctx << "NULL";
+        } else if (env->IsInstanceOf(item, gStringClass)) {
+            const char *str = env->GetStringUTFChars((jstring) item, NULL);
+            ctx << str;
+            env->ReleaseStringUTFChars((jstring) item, str);
         } else if (env->IsInstanceOf(item, gIntegerClass)) {
-            jint intVal = env->GetIntField(item, gIntegerValueID);
-            if (pos + 1 + sizeof(intVal) > max) break;
-            buf[pos++] = EVENT_TYPE_INT;
-            memcpy(&buf[pos], &intVal, sizeof(intVal));
-            pos += sizeof(intVal);
+            ctx << (int32_t)env->GetIntField(item, gIntegerValueID);
         } else if (env->IsInstanceOf(item, gLongClass)) {
-            jlong longVal = env->GetLongField(item, gLongValueID);
-            if (pos + 1 + sizeof(longVal) > max) break;
-            buf[pos++] = EVENT_TYPE_LONG;
-            memcpy(&buf[pos], &longVal, sizeof(longVal));
-            pos += sizeof(longVal);
+            ctx << (int64_t)env->GetLongField(item, gLongValueID);
         } else if (env->IsInstanceOf(item, gFloatClass)) {
-            jfloat floatVal = env->GetFloatField(item, gFloatValueID);
-            if (pos + 1 + sizeof(floatVal) > max) break;
-            buf[pos++] = EVENT_TYPE_FLOAT;
-            memcpy(&buf[pos], &floatVal, sizeof(floatVal));
-            pos += sizeof(floatVal);
+            ctx << (float)env->GetFloatField(item, gFloatValueID);
         } else {
             jniThrowException(env,
                     "java/lang/IllegalArgumentException",
@@ -156,11 +139,7 @@
         }
         env->DeleteLocalRef(item);
     }
-
-    buf[0] = EVENT_TYPE_LIST;
-    buf[1] = copied;
-    buf[pos++] = '\n';
-    return android_bWriteLog(tag, buf, pos);
+    return ctx.write();
 }
 
 /*
diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp
index b9376d8..4b105ca 100644
--- a/core/jni/android_view_GraphicBuffer.cpp
+++ b/core/jni/android_view_GraphicBuffer.cpp
@@ -22,6 +22,7 @@
 #include "android_os_Parcel.h"
 #include "android_view_GraphicBuffer.h"
 #include "android/graphics/GraphicsJNI.h"
+#include "Bitmap.h"
 
 #include <android_runtime/AndroidRuntime.h>
 
@@ -32,6 +33,7 @@
 
 #include <gui/IGraphicBufferAlloc.h>
 #include <gui/ISurfaceComposer.h>
+#include <hwui/Bitmap.h>
 
 #include <SkCanvas.h>
 #include <SkBitmap.h>
@@ -247,6 +249,17 @@
     return NULL;
 }
 
+static jobject android_view_GraphicBuffer_createHardwareBitmap(JNIEnv* env, jobject,
+        jlong wrapperHandle) {
+    GraphicBufferWrapper* wrapper = reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
+    sk_sp<Bitmap> bitmap = Bitmap::createFrom(wrapper->buffer);
+    if (!bitmap.get()) {
+        ALOGW("failed to create hardware bitmap from graphic buffer");
+        return NULL;
+    }
+    return bitmap::createBitmap(env, bitmap.release(), android::bitmap::kBitmapCreateFlag_None);
+}
+
 // ----------------------------------------------------------------------------
 // External helpers
 // ----------------------------------------------------------------------------
@@ -282,6 +295,9 @@
             (void*) android_view_GraphicBuffer_lockCanvas },
     { "nUnlockCanvasAndPost", "(JLandroid/graphics/Canvas;)Z",
             (void*) android_view_GraphicBuffer_unlockCanvasAndPost },
+    { "nCreateHardwareBitmap", "(J)Landroid/graphics/Bitmap;",
+        (void*) android_view_GraphicBuffer_createHardwareBitmap
+    }
 };
 
 int register_android_view_GraphicBuffer(JNIEnv* env) {
diff --git a/core/jni/com_android_internal_os_FuseAppLoop.cpp b/core/jni/com_android_internal_os_FuseAppLoop.cpp
new file mode 100644
index 0000000..92a6934
--- /dev/null
+++ b/core/jni/com_android_internal_os_FuseAppLoop.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "FuseAppLoopJNI"
+#define LOG_NDEBUG 0
+
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include <android_runtime/Log.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <jni.h>
+#include <libappfuse/FuseAppLoop.h>
+#include <nativehelper/ScopedLocalRef.h>
+
+#include "core_jni_helpers.h"
+
+namespace android {
+
+namespace {
+
+constexpr const char* CLASS_NAME = "com/android/internal/os/FuseAppLoop";
+
+jclass gFuseAppLoopClass;
+jmethodID gOnGetSizeMethod;
+jmethodID gOnOpenMethod;
+jmethodID gOnFsyncMethod;
+jmethodID gOnReleaseMethod;
+jmethodID gOnReadMethod;
+jmethodID gOnWriteMethod;
+
+class Callback : public fuse::FuseAppLoopCallback {
+private:
+    static constexpr size_t kBufferSize = std::max(fuse::kFuseMaxWrite, fuse::kFuseMaxRead);
+    static_assert(kBufferSize <= INT32_MAX, "kBufferSize should be fit in int32_t.");
+
+    JNIEnv* const mEnv;
+    jobject const mSelf;
+    ScopedLocalRef<jbyteArray> mJniBuffer;
+    bool mActive;
+
+    template <typename T>
+    T checkException(T result) const {
+        if (mEnv->ExceptionCheck()) {
+            LOGE_EX(mEnv, nullptr);
+            mEnv->ExceptionClear();
+            return -EIO;
+        }
+        return result;
+    }
+
+public:
+    Callback(JNIEnv* env, jobject self) :
+        mEnv(env),
+        mSelf(self),
+        mJniBuffer(env, nullptr),
+        mActive(true) {}
+
+    bool Init() {
+        mJniBuffer.reset(mEnv->NewByteArray(kBufferSize));
+        return mJniBuffer.get();
+    }
+
+    bool IsActive() override {
+        return mActive;
+    }
+
+    int64_t OnGetSize(uint64_t inode) override {
+        return checkException(mEnv->CallLongMethod(mSelf, gOnGetSizeMethod, inode));
+    }
+
+    int32_t OnOpen(uint64_t inode) override {
+        return checkException(mEnv->CallIntMethod(mSelf, gOnOpenMethod, inode));
+    }
+
+    int32_t OnFsync(uint64_t inode) override {
+        return checkException(mEnv->CallIntMethod(mSelf, gOnFsyncMethod, inode));
+    }
+
+    int32_t OnRelease(uint64_t inode) override {
+        if (checkException(mEnv->CallIntMethod(mSelf, gOnReleaseMethod, inode)) == -1) {
+            mActive = false;
+        }
+        return fuse::kFuseSuccess;
+    }
+
+    int32_t OnRead(uint64_t inode, uint64_t offset, uint32_t size, void* buffer) override {
+        CHECK_LE(size, static_cast<uint32_t>(kBufferSize));
+        const int32_t result = checkException(mEnv->CallIntMethod(
+                mSelf, gOnReadMethod, inode, offset, size, mJniBuffer.get()));
+        if (result <= 0) {
+            return result;
+        }
+        if (result > static_cast<int32_t>(size)) {
+            LOG(ERROR) << "Returned size is too large.";
+            return -EIO;
+        }
+
+        mEnv->GetByteArrayRegion(mJniBuffer.get(), 0, result, static_cast<jbyte*>(buffer));
+        CHECK(!mEnv->ExceptionCheck());
+
+        return checkException(result);
+    }
+
+    int32_t OnWrite(uint64_t inode, uint64_t offset, uint32_t size, const void* buffer) override {
+        CHECK_LE(size, static_cast<uint32_t>(kBufferSize));
+
+        mEnv->SetByteArrayRegion(mJniBuffer.get(), 0, size, static_cast<const jbyte*>(buffer));
+        CHECK(!mEnv->ExceptionCheck());
+
+        return checkException(mEnv->CallIntMethod(
+                mSelf, gOnWriteMethod, inode, offset, size, mJniBuffer.get()));
+    }
+};
+
+jboolean com_android_internal_os_FuseAppLoop_start_loop(JNIEnv* env, jobject self, jint jfd) {
+    base::unique_fd fd(jfd);
+    Callback callback(env, self);
+
+    if (!callback.Init()) {
+        LOG(ERROR) << "Failed to init callback";
+        return JNI_FALSE;
+    }
+
+    return fuse::StartFuseAppLoop(fd.release(), &callback);
+}
+
+const JNINativeMethod methods[] = {
+    {
+        "native_start_loop",
+        "(I)Z",
+        (void *) com_android_internal_os_FuseAppLoop_start_loop
+    }
+};
+
+}  // namespace
+
+int register_com_android_internal_os_FuseAppLoop(JNIEnv* env) {
+    gFuseAppLoopClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, CLASS_NAME));
+    gOnGetSizeMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onGetSize", "(J)J");
+    gOnOpenMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onOpen", "(J)I");
+    gOnFsyncMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onFsync", "(J)I");
+    gOnReleaseMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onRelease", "(J)I");
+    gOnReadMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onRead", "(JJI[B)I");
+    gOnWriteMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onWrite", "(JJI[B)I");
+    RegisterMethodsOrDie(env, CLASS_NAME, methods, NELEM(methods));
+    return 0;
+}
+
+}  // namespace android
diff --git a/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp b/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
index 6781e13..f4d2e7b 100644
--- a/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
+++ b/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
@@ -18,6 +18,7 @@
 
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
+#include <cutils/log.h>
 #include "core_jni_helpers.h"
 
 #include <Interpolator.h>
@@ -62,6 +63,19 @@
     return reinterpret_cast<jlong>(new OvershootInterpolator(tension));
 }
 
+static jlong createPathInterpolator(JNIEnv* env, jobject clazz, jfloatArray jX, jfloatArray jY) {
+    jsize lenX = env->GetArrayLength(jX);
+    jsize lenY = env->GetArrayLength(jY);
+    LOG_ALWAYS_FATAL_IF(lenX != lenY || lenX <= 0, "Invalid path interpolator, x size: %d,"
+            " y size: %d", lenX, lenY);
+    std::vector<float> x(lenX);
+    std::vector<float> y(lenY);
+    env->GetFloatArrayRegion(jX, 0, lenX, x.data());
+    env->GetFloatArrayRegion(jY, 0, lenX, y.data());
+
+    return reinterpret_cast<jlong>(new PathInterpolator(std::move(x), std::move(y)));
+}
+
 static jlong createLutInterpolator(JNIEnv* env, jobject clazz, jfloatArray jlut) {
     jsize len = env->GetArrayLength(jlut);
     if (len <= 0) {
@@ -88,6 +102,7 @@
     { "createDecelerateInterpolator", "(F)J", (void*) createDecelerateInterpolator },
     { "createLinearInterpolator", "()J", (void*) createLinearInterpolator },
     { "createOvershootInterpolator", "(F)J", (void*) createOvershootInterpolator },
+    { "createPathInterpolator", "([F[F)J", (void*) createPathInterpolator },
     { "createLutInterpolator", "([F)J", (void*) createLutInterpolator },
 };
 
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 3d63b01..56bec18 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -254,59 +254,11 @@
     return reinterpret_cast<jlong>(sur);
 }
 
-static PixelFormat convertPixelFormat(SkColorType format)
-{
-    switch (format) {
-    case kN32_SkColorType:         return PIXEL_FORMAT_RGBA_8888;
-    case kARGB_4444_SkColorType:   return PIXEL_FORMAT_RGBA_4444;
-    case kRGB_565_SkColorType:     return PIXEL_FORMAT_RGB_565;
-    default:                       return PIXEL_FORMAT_NONE;
-    }
-}
-
 static void jni_eglCreatePixmapSurface(JNIEnv *_env, jobject _this, jobject out_sur,
         jobject display, jobject config, jobject native_pixmap,
         jintArray attrib_list)
 {
-    if (display == NULL || config == NULL || native_pixmap == NULL
-        || !validAttribList(_env, attrib_list)) {
-        jniThrowException(_env, "java/lang/IllegalArgumentException", NULL);
-        return;
-    }
-    EGLDisplay dpy = getDisplay(_env, display);
-    EGLConfig  cnf = getConfig(_env, config);
-    jint* base = 0;
-
-    SkBitmap nativeBitmap;
-    GraphicsJNI::getSkBitmap(_env, native_pixmap, &nativeBitmap);
-    SkPixelRef* ref = nativeBitmap.pixelRef();
-    if (ref == NULL) {
-        jniThrowException(_env, "java/lang/IllegalArgumentException", "Bitmap has no PixelRef");
-        return;
-    }
-
-    SkSafeRef(ref);
-    ref->lockPixels();
-
-    egl_native_pixmap_t pixmap;
-    pixmap.version = sizeof(pixmap);
-    pixmap.width  = nativeBitmap.width();
-    pixmap.height = nativeBitmap.height();
-    pixmap.stride = nativeBitmap.rowBytes() / nativeBitmap.bytesPerPixel();
-    pixmap.format = convertPixelFormat(nativeBitmap.colorType());
-    pixmap.data   = (uint8_t*)ref->pixels();
-
-    base = beginNativeAttribList(_env, attrib_list);
-    EGLSurface sur = eglCreatePixmapSurface(dpy, cnf, &pixmap, base);
-    endNativeAttributeList(_env, attrib_list, base);
-
-    if (sur != EGL_NO_SURFACE) {
-        _env->SetLongField(out_sur, gSurface_EGLSurfaceFieldID, reinterpret_cast<jlong>(sur));
-        _env->SetLongField(out_sur, gSurface_NativePixelRefFieldID, reinterpret_cast<jlong>(ref));
-    } else {
-        ref->unlockPixels();
-        SkSafeUnref(ref);
-    }
+    jniThrowException(_env, "java/lang/UnsupportedOperationException", "eglCreatePixmapSurface");
 }
 
 static jlong jni_eglCreateWindowSurface(JNIEnv *_env, jobject _this, jobject display,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index fbad143..62ff85d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -182,6 +182,10 @@
         android:name="android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS" />
     <protected-broadcast
         android:name="android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED" />
+    <protected-broadcast android:name="android.bluetooth.mapmce.profile.action.CONNECTION_STATE_CHANGED" />
+    <protected-broadcast android:name="android.bluetooth.mapmce.profile.action.MESSAGE_RECEIVED" />
+    <protected-broadcast android:name="android.bluetooth.mapmce.profile.action.MESSAGE_SENT_SUCCESSFULLY" />
+    <protected-broadcast android:name="android.bluetooth.mapmce.profile.action.MESSAGE_DELIVERED_SUCCESSFULLY" />
     <protected-broadcast
         android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_SENT" />
     <protected-broadcast
@@ -189,6 +193,7 @@
     <protected-broadcast
         android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.pbap.intent.action.PBAP_STATE_CHANGED" />
+    <protected-broadcast android:name="android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast android:name="android.btopp.intent.action.INCOMING_FILE_NOTIFICATION" />
     <protected-broadcast android:name="android.btopp.intent.action.USER_CONFIRMATION_TIMEOUT" />
@@ -769,6 +774,15 @@
         android:permissionGroup="android.permission-group.PHONE"
         android:label="@string/permlab_readPhoneState"
         android:description="@string/permdesc_readPhoneState"
+        android:protectionLevel="dangerous" />
+
+    <!-- Allows read access to the device's phone number. This is a subset of the capabilities
+         granted by {@link #READ_PHONE_STATE} but is exposed to ephemeral applications.
+         <p>Protection level: dangerous-->
+    <permission android:name="android.permission.READ_PHONE_NUMBER"
+        android:permissionGroup="android.permission-group.PHONE"
+        android:label="@string/permlab_readPhoneNumber"
+        android:description="@string/permdesc_readPhoneNumber"
         android:protectionLevel="dangerous|ephemeral" />
 
     <!-- Allows an application to initiate a phone call without going through
@@ -928,7 +942,7 @@
         android:permissionGroup="android.permission-group.CAMERA"
         android:label="@string/permlab_camera"
         android:description="@string/permdesc_camera"
-        android:protectionLevel="dangerous" />
+        android:protectionLevel="dangerous|ephemeral" />
 
 
     <!-- ====================================================================== -->
@@ -1178,7 +1192,7 @@
     <permission android:name="android.permission.ACCESS_NETWORK_STATE"
         android:description="@string/permdesc_accessNetworkState"
         android:label="@string/permlab_accessNetworkState"
-        android:protectionLevel="normal" />
+        android:protectionLevel="normal|ephemeral" />
 
     <!-- Allows applications to access information about Wi-Fi networks.
          <p>Protection level: normal
diff --git a/core/res/res/anim/slide_in_enter_micro.xml b/core/res/res/anim/slide_in_enter_micro.xml
index c70874c..6e7df4f 100644
--- a/core/res/res/anim/slide_in_enter_micro.xml
+++ b/core/res/res/anim/slide_in_enter_micro.xml
@@ -19,7 +19,7 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
      android:zAdjustment="top">
-    <translate android:fromYDelta="5%p" android:toYDelta="0"
+    <translate android:fromXDelta="5%p" android:toXDelta="0"
                android:duration="417"
                android:interpolator="@android:interpolator/launch_task_micro_ydelta" />
     <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
diff --git a/core/res/res/anim/slide_out_micro.xml b/core/res/res/anim/slide_out_micro.xml
index c647093..cccf697 100644
--- a/core/res/res/anim/slide_out_micro.xml
+++ b/core/res/res/anim/slide_out_micro.xml
@@ -19,8 +19,8 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-     android:zAdjustment="top">
-    <translate android:fromYDelta="0" android:toYDelta="5%p"
+     android:zAdjustment="normal">
+    <translate android:fromXDelta="0" android:toXDelta="5%p"
                android:duration="250"
                android:interpolator="@android:interpolator/fast_out_slow_in"/>
     <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
diff --git a/core/res/res/drawable/ic_corp_badge_case.xml b/core/res/res/drawable/ic_corp_badge_case.xml
new file mode 100644
index 0000000..0b6028c
--- /dev/null
+++ b/core/res/res/drawable/ic_corp_badge_case.xml
@@ -0,0 +1,30 @@
+<!--
+Copyright (C) 2016 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="20.0dp"
+        android:height="20.0dp"
+        android:viewportWidth="20.0"
+        android:viewportHeight="20.0">
+    <path
+        android:pathData="M15.2,6.2L4.8,6.2c-0.5,0.0 -0.9,0.4 -0.9,1.0L3.9,10.0c0.0,0.5 0.4,1.0 0.9,1.0l3.8,0.0l0.0,-1.0l2.9,0.0l0.0,1.0l3.8,0.0c0.5,0.0 1.0,-0.4 1.0,-1.0L16.3,7.1C16.2,6.6 15.8,6.2 15.2,6.2z"
+        android:fillColor="#FFFFFF"/>
+    <path
+        android:pathData="M8.6,12.9l0.0,-1.0L4.3,11.9l0.0,2.4c0.0,0.5 0.4,0.9 0.9,0.9l9.5,0.0c0.5,0.0 0.9,-0.4 0.9,-0.9l0.0,-2.4l-4.3,0.0l0.0,1.0L8.6,12.9z"
+        android:fillColor="#FFFFFF"/>
+    <path
+        android:pathData="M7.1,5.2l0.0,1.0 1.0,0.0 0.0,-1.0 3.799999,0.0 0.0,1.0 1.0,0.0 0.0,-1.0 -1.0,-0.9 -3.799999,0.0z"
+        android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/core/res/res/drawable/ic_corp_badge_color.xml b/core/res/res/drawable/ic_corp_badge_color.xml
new file mode 100644
index 0000000..b6c7969
--- /dev/null
+++ b/core/res/res/drawable/ic_corp_badge_color.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2016 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="20.0dp"
+        android:height="20.0dp"
+        android:viewportWidth="20.0"
+        android:viewportHeight="20.0">
+    <path
+        android:pathData="M10.0,10.0m-10.0,0.0a10.0,10.0 0.0,1.0 1.0,20.0 0.0a10.0,10.0 0.0,1.0 1.0,-20.0 0.0"
+        android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/core/res/res/drawable/ic_corp_badge_no_background.xml b/core/res/res/drawable/ic_corp_badge_no_background.xml
index b1bddfc..78322a9 100644
--- a/core/res/res/drawable/ic_corp_badge_no_background.xml
+++ b/core/res/res/drawable/ic_corp_badge_no_background.xml
@@ -20,11 +20,11 @@
     android:viewportHeight="24.0">
     <path
         android:pathData="M20.801,5.981L17.13,5.98l0.001,-1.471l-2.053,-2.055L8.969,2.453L6.915,4.506L6.914,5.977L3.203,5.976c-1.216,0.0 -2.189,0.983 -2.189,2.199L1.0,12.406c0.0,1.216 0.983,2.2 2.199,2.2L10.0,14.608l0.0,-1.644l0.291,0.0l3.351,0.0l0.291,0.0l0.0,1.645l6.863,0.002c1.216,0.0 2.2,-0.983 2.2,-2.199L23.0,8.181C23.0,6.965 22.017,5.981 20.801,5.981zM15.076,5.979L8.968,5.978l0.001,-1.471l6.108,0.001L15.076,5.979z"
-        android:fillColor="#FF5722"/>
+        android:fillColor="#FFFFFF"/>
     <path
         android:pathData="M13.911,16.646L9.978,16.646L9.978,15.48L1.673,15.48l0.0,4.105c0.0,1.216 0.959,2.2 2.175,2.2l16.13,0.004c1.216,0.0 2.203,-0.983 2.203,-2.199l0.0,-4.11l-8.27,0.0L13.910999,16.646z"
-        android:fillColor="#FF5722"/>
+        android:fillColor="#FFFFFF"/>
     <path
         android:pathData="M23.657,6.55 h4.72 v1.137 h-4.72z"
         android:fillColor="#00000000"/>
-</vector>
\ No newline at end of file
+</vector>
diff --git a/core/res/res/drawable/ic_corp_icon_badge.xml b/core/res/res/drawable/ic_corp_icon_badge_case.xml
similarity index 71%
rename from core/res/res/drawable/ic_corp_icon_badge.xml
rename to core/res/res/drawable/ic_corp_icon_badge_case.xml
index 0273545..d62eda4 100644
--- a/core/res/res/drawable/ic_corp_icon_badge.xml
+++ b/core/res/res/drawable/ic_corp_icon_badge_case.xml
@@ -1,5 +1,5 @@
 <!--
-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.
@@ -19,17 +19,6 @@
         android:viewportWidth="64.0"
         android:viewportHeight="64.0">
     <path
-        android:fillColor="#FF000000"
-        android:pathData="M49.1,50.1m-13.9,0.0a13.9,13.9 0.0,1.0 1.0,27.8 0.0a13.9,13.9 0.0,1.0 1.0,-27.8 0.0"
-        android:fillAlpha="0.2"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M49.1,49.4m-13.9,0.0a13.9,13.9 0.0,1.0 1.0,27.8 0.0a13.9,13.9 0.0,1.0 1.0,-27.8 0.0"
-        android:fillAlpha="0.2"/>
-    <path
-        android:pathData="M49.1,48.8m-13.9,0.0a13.9,13.9 0.0,1.0 1.0,27.8 0.0a13.9,13.9 0.0,1.0 1.0,-27.8 0.0"
-        android:fillColor="#FF5722"/>
-    <path
         android:pathData="M56.4,43.5L41.8,43.5c-0.7,0.0 -1.3,0.6 -1.3,1.3l0.0,4.0c0.0,0.7 0.6,1.3 1.3,1.3L47.0,50.1l0.0,-1.3l4.0,0.0l0.0,1.4l5.4,0.0c0.7,0.0 1.3,-0.6 1.3,-1.3l0.0,-4.0C57.6,44.1 57.0,43.5 56.4,43.5z"
         android:fillColor="#FFFFFF"/>
     <path
diff --git a/core/res/res/drawable/ic_corp_icon_badge_color.xml b/core/res/res/drawable/ic_corp_icon_badge_color.xml
new file mode 100644
index 0000000..3bc4e67
--- /dev/null
+++ b/core/res/res/drawable/ic_corp_icon_badge_color.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2016 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="64.0dp"
+        android:height="64.0dp"
+        android:viewportWidth="64.0"
+        android:viewportHeight="64.0">
+    <path
+        android:pathData="M49.1,48.8m-13.9,0.0a13.9,13.9 0.0,1.0 1.0,27.8 0.0a13.9,13.9 0.0,1.0 1.0,-27.8 0.0"
+        android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/core/res/res/drawable/ic_corp_icon_badge_shadow.xml b/core/res/res/drawable/ic_corp_icon_badge_shadow.xml
new file mode 100644
index 0000000..a546cdd
--- /dev/null
+++ b/core/res/res/drawable/ic_corp_icon_badge_shadow.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="64.0dp"
+        android:height="64.0dp"
+        android:viewportWidth="64.0"
+        android:viewportHeight="64.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M49.1,50.1m-13.9,0.0a13.9,13.9 0.0,1.0 1.0,27.8 0.0a13.9,13.9 0.0,1.0 1.0,-27.8 0.0"
+        android:fillAlpha="0.2"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M49.1,49.4m-13.9,0.0a13.9,13.9 0.0,1.0 1.0,27.8 0.0a13.9,13.9 0.0,1.0 1.0,-27.8 0.0"
+        android:fillAlpha="0.2"/>
+</vector>
diff --git a/core/res/res/layout/date_picker_material.xml b/core/res/res/layout/date_picker_material.xml
index 763f2a4..dd8a45d2 100644
--- a/core/res/res/layout/date_picker_material.xml
+++ b/core/res/res/layout/date_picker_material.xml
@@ -25,10 +25,16 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content" />
 
-    <include
-        layout="@layout/date_picker_view_animator_material"
-        android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:layout_weight="1" />
+    <ScrollView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:fadeScrollbars="false"
+        android:scrollIndicators="top|bottom">
+        <include
+            layout="@layout/date_picker_view_animator_material"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1" />
+    </ScrollView>
 
 </LinearLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index b2212f9..a24bce1 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Mediavolume"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Kennisgewing-volume"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Verstekluitoon"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Verstek (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Geen"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Luitone"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Wekkerklanke"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Kennisgewingsklanke"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Onbekend"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Wi-Fi netwerke beskikbaar</item>
       <item quantity="one">Wi-Fi-netwerk beskikbaar</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Kies jaar"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> uitgevee"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Werk-<xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Raak en hou Terug om hierdie skerm te ontspeld."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Program is vasgespeld: Dit mag nie op hierdie toestel ontspeld word nie."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Skerm vasgespeld"</string>
@@ -1683,6 +1683,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Stel nou terug"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Het <xliff:g id="LABEL">%1$s</xliff:g> gedeaktiveer"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferensie-oproep"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Nutswenk-opspringer"</string>
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 2b92730..6bab82c 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"የማህደረ መረጃ ክፍልፍል"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"የማሳወቂያ ክፍልፍል"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"ነባሪ የስልክ ላይ ጥሪ"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"ነባሪ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"ምንም"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"ጥሪ ድምፆች"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"የማንቂያ ድምጾች"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"የማሳወቂያ ድምፆች"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"ያልታወቀ"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">የWi-Fi አውታረ መረቦች አሉ</item>
       <item quantity="other">የWi-Fi አውታረ መረቦች አሉ</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"ዓመት ይምረጡ"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> ተሰርዟል"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"ስራ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"ይህን ማያ ገጽ ለመንቀል ተመለስን ይንኩትና ያዙት።"</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"መተግበሪያ ተሰክቷል፦ በዚህ መሣሪያ ላይ ማላቀቅ አይፈቀድም።"</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"ማያ ገጽ ተሰክቷል"</string>
@@ -1683,6 +1683,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>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"የመሣሪያ ጥቆማ ብቅ-ባይ"</string>
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index b2835cc..7c9baeb 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1151,16 +1151,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"مستوى صوت الوسائط"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"مستوى صوت الإشعار"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"نغمة الرنين الافتراضية"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"الافتراضية (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"لا شيء"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"نغمات الرنين"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"أصوات التنبيه"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"أصوات الإشعار"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"غير معروف"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="zero">‏لا تتوفر أية شبكات Wi-Fi</item>
       <item quantity="two">‏تتوفر شبكتا Wi-Fi</item>
@@ -1672,6 +1668,10 @@
     <string name="select_year" msgid="7952052866994196170">"تحديد العام"</string>
     <string name="deleted_key" msgid="7659477886625566590">"تم حذف <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> المخصص للعمل"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"لإزالة تثبيت هذه الشاشة، يمكنك لمس زر الرجوع مع الاستمرار."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"التطبيق مقيد: ولا يسمح بإلغاء التقييد على هذا الجهاز."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"تم تثبيت الشاشة"</string>
@@ -1827,6 +1827,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>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"نافذة منبثقة لتلميح"</string>
 </resources>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 5d09077..11133d1 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Media həcmi"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Bildiriş səsi"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Defolt rinqton"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Defolt (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Heç biri"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Zəng səsləri"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Zəngli saat səsləri"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Bildiriş səsləri"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Naməlum"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Əlçatan Wi-Fi şəbəkələri</item>
       <item quantity="one">Əlçatan Wi-Fi şəbəkəsi</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"İl seçin"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> silindi"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"İş <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Sancağı götürmək üçün Geri düyməsinə toxunun və saxlayın."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Tətbiq sancılıb: Açmağa bu cihazda icazə verilmir."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Screen pinned"</string>
@@ -1683,6 +1683,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"İndi sıfırlayın"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> deaktiv edildi"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konfrans Zəngi"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Tooltip Popap"</string>
 </resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index b65ed4d..d2799c4 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1082,16 +1082,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Jačina zvuka medija"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Jačina zvuka obaveštenja"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Podrazumevani zvuk zvona"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Podrazumevano (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Bez zvuka"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Zvukovi zvona"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Zvuci alarma"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Zvuci obaveštenja"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Nepoznato"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">Wi-Fi mreže su dostupne</item>
       <item quantity="few">Wi-Fi mreže su dostupne</item>
@@ -1591,6 +1587,10 @@
     <string name="select_year" msgid="7952052866994196170">"Izaberite godinu"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Izbrisali ste <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> na poslu"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Da biste otkačili ovaj ekran, dodirnite i zadržite Nazad."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Aplikacija je zakačena: otkačinjanje nije dozvoljeno na ovom uređaju."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ekran je zakačen"</string>
@@ -1719,6 +1719,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Resetuj"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Vidžet <xliff:g id="LABEL">%1$s</xliff:g> je onemogućen"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferencijski poziv"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Iskačuće objašnjenje"</string>
 </resources>
diff --git a/core/res/res/values-be-rBY/strings.xml b/core/res/res/values-be-rBY/strings.xml
index 63359a1..a7be24e 100644
--- a/core/res/res/values-be-rBY/strings.xml
+++ b/core/res/res/values-be-rBY/strings.xml
@@ -1105,16 +1105,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Гучнасць прайгравальніка"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Гучнасць апавяшчэнняў"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Стандартны рынгтон"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Стандартны (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Няма"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Рынгтоны"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Гукі будзільніка"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Гукі апавяшчэнняў"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Невядома"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">сетка Wi-Fi даступная</item>
       <item quantity="few">сеткі Wi-Fi даступныя</item>
@@ -1618,6 +1614,10 @@
     <string name="select_year" msgid="7952052866994196170">"Выберыце год"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Выдалена: <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (праца)"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Каб адмацаваць гэты экран, дакраніцеся і ўтрымлівайце кнопку \"Назад\"."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Праграма замацавана: адмацаванне на гэтай прыладзе не дапускаецца."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Экран замацаваны"</string>
@@ -1755,6 +1755,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>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Усплывальная падказка"</string>
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index a818b7e..1900b074 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Сила на звука"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Сила на звука при известие"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Стандартна мелодия"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"По подразбиране (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Без"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Мелодии"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Звуци на будилника"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Звуци на известията"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Няма информация"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Има достъпни Wi-Fi мрежи</item>
       <item quantity="one">Има достъпна Wi-Fi мрежа</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Избиране на година"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Изтрихте <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> за работа"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"За да освободите този екран, докоснете и задръжте бутона за връщане назад."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Приложението е фиксирано. Освобождаването му не е разрешено на това устройство."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Екранът е фиксиран"</string>
@@ -1683,6 +1683,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>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Изскачащ прозорец с подсказка"</string>
 </resources>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index 20343af..bdbea68 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"বছর নির্বাচন করুন"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> মুছে ফেলা হয়েছে"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"কর্মক্ষেত্র <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"এই স্ক্রীনটিকে আনপিন করতে, \'ফিরুন\' স্পর্শ করুন এবং ধরে রাখুন৷"</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"অ্যাপ্লিকেশান পিন করা আছে: এই ডিভাইস এটিকে পিনমুক্ত করা মঞ্জুরিপ্রাপ্ত নয়৷"</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"স্ক্রীন পিন করা হয়েছে"</string>
diff --git a/core/res/res/values-bs-rBA/strings.xml b/core/res/res/values-bs-rBA/strings.xml
index 205bffb..f62dac7 100644
--- a/core/res/res/values-bs-rBA/strings.xml
+++ b/core/res/res/values-bs-rBA/strings.xml
@@ -551,35 +551,35 @@
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Kuća"</item>
     <item msgid="869923650527136615">"Mobilni"</item>
-    <item msgid="7897544654242874543">"Poslovni"</item>
+    <item msgid="7897544654242874543">"Posao"</item>
     <item msgid="1103601433382158155">"Poslovni faks"</item>
     <item msgid="1735177144948329370">"Kućni faks"</item>
     <item msgid="603878674477207394">"Pejdžer"</item>
     <item msgid="1650824275177931637">"Ostalo"</item>
-    <item msgid="9192514806975898961">"Dodatno"</item>
+    <item msgid="9192514806975898961">"Prilagođeno"</item>
   </string-array>
   <string-array name="emailAddressTypes">
     <item msgid="8073994352956129127">"Kućni"</item>
-    <item msgid="7084237356602625604">"Poslovni"</item>
-    <item msgid="1112044410659011023">"Ostali"</item>
-    <item msgid="2374913952870110618">"Dodatni"</item>
+    <item msgid="7084237356602625604">"Posao"</item>
+    <item msgid="1112044410659011023">"Ostalo"</item>
+    <item msgid="2374913952870110618">"Prilagođeno"</item>
   </string-array>
   <string-array name="postalAddressTypes">
     <item msgid="6880257626740047286">"Kuća"</item>
     <item msgid="5629153956045109251">"Posao"</item>
     <item msgid="4966604264500343469">"Ostalo"</item>
-    <item msgid="4932682847595299369">"Dodatno"</item>
+    <item msgid="4932682847595299369">"Prilagođeno"</item>
   </string-array>
   <string-array name="imAddressTypes">
     <item msgid="1738585194601476694">"Kućni"</item>
-    <item msgid="1359644565647383708">"Poslovni"</item>
-    <item msgid="7868549401053615677">"Ostali"</item>
-    <item msgid="3145118944639869809">"Dodatni"</item>
+    <item msgid="1359644565647383708">"Posao"</item>
+    <item msgid="7868549401053615677">"Ostalo"</item>
+    <item msgid="3145118944639869809">"Prilagođeno"</item>
   </string-array>
   <string-array name="organizationTypes">
     <item msgid="7546335612189115615">"Posao"</item>
     <item msgid="4378074129049520373">"Ostalo"</item>
-    <item msgid="3455047468583965104">"Dodatno"</item>
+    <item msgid="3455047468583965104">"Prilagođeno"</item>
   </string-array>
   <string-array name="imProtocols">
     <item msgid="8595261363518459565">"AIM"</item>
@@ -600,15 +600,15 @@
     <string name="phoneTypePager" msgid="7582359955394921732">"Pejdžer"</string>
     <string name="phoneTypeOther" msgid="1544425847868765990">"Ostalo"</string>
     <string name="phoneTypeCallback" msgid="2712175203065678206">"Povratni poziv"</string>
-    <string name="phoneTypeCar" msgid="8738360689616716982">"Auto"</string>
-    <string name="phoneTypeCompanyMain" msgid="540434356461478916">"Glavni broj kompanije"</string>
+    <string name="phoneTypeCar" msgid="8738360689616716982">"Automobil"</string>
+    <string name="phoneTypeCompanyMain" msgid="540434356461478916">"Poslovni glavni"</string>
     <string name="phoneTypeIsdn" msgid="8022453193171370337">"ISDN"</string>
     <string name="phoneTypeMain" msgid="6766137010628326916">"Glavni"</string>
     <string name="phoneTypeOtherFax" msgid="8587657145072446565">"Drugi faks"</string>
     <string name="phoneTypeRadio" msgid="4093738079908667513">"Radio"</string>
     <string name="phoneTypeTelex" msgid="3367879952476250512">"Teleks"</string>
     <string name="phoneTypeTtyTdd" msgid="8606514378585000044">"TTY TDD"</string>
-    <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"Posao mobilni"</string>
+    <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"Poslovni mobilni"</string>
     <string name="phoneTypeWorkPager" msgid="649938731231157056">"Poslovni pejdžer"</string>
     <string name="phoneTypeAssistant" msgid="5596772636128562884">"Pomoćnik"</string>
     <string name="phoneTypeMms" msgid="7254492275502768992">"MMS"</string>
@@ -616,10 +616,10 @@
     <string name="eventTypeBirthday" msgid="2813379844211390740">"Rođendan"</string>
     <string name="eventTypeAnniversary" msgid="3876779744518284000">"Godišnjica"</string>
     <string name="eventTypeOther" msgid="7388178939010143077">"Ostalo"</string>
-    <string name="emailTypeCustom" msgid="8525960257804213846">"Prilagođeni"</string>
+    <string name="emailTypeCustom" msgid="8525960257804213846">"Prilagođeno"</string>
     <string name="emailTypeHome" msgid="449227236140433919">"Kućni"</string>
-    <string name="emailTypeWork" msgid="3548058059601149973">"Poslovni"</string>
-    <string name="emailTypeOther" msgid="2923008695272639549">"Ostali"</string>
+    <string name="emailTypeWork" msgid="3548058059601149973">"Posao"</string>
+    <string name="emailTypeOther" msgid="2923008695272639549">"Ostalo"</string>
     <string name="emailTypeMobile" msgid="119919005321166205">"Mobilni"</string>
     <string name="postalTypeCustom" msgid="8903206903060479902">"Prilagođeno"</string>
     <string name="postalTypeHome" msgid="8165756977184483097">"Kućna adresa"</string>
@@ -1084,16 +1084,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Jačina zvuka za medijske sadržaje"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Jačina zvuka za obavještenja"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Zadana melodija zvona"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Zadano (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Bez zvuka"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Melodije zvona"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Zvuci alarma"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Zvuci obavještenja"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Nepoznato"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">Wi-Fi mreže su dostupne</item>
       <item quantity="few">Wi-Fi mreže su dostupne</item>
@@ -1593,6 +1589,10 @@
     <string name="select_year" msgid="7952052866994196170">"Odaberite godinu"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Broj <xliff:g id="KEY">%1$s</xliff:g> je izbrisan"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Poslovni <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Da biste otkačili ovaj ekran, dodirnite i držite dugme Nazad."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Aplikacija je prikačena. Na ovom uređaju nije dozvoljeno otkačivanje."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ekran je zakačen"</string>
@@ -1721,6 +1721,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Vrati sada na početne postavke"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Onemogućen <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferencijski poziv"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Iskočni prozor sa savjetom u vezi alata"</string>
 </resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index a1797cb..f335d44 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Volum de multimèdia"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volum de notificació"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"So predeterminat"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Predeterminat (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Cap"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Sons"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sons de l\'alarma"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sons de notificació"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Desconegut"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Xarxes Wi-Fi disponibles</item>
       <item quantity="one">Xarxa Wi-Fi disponible</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Selecciona un any"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> suprimit"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de la feina"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Toca i mantén premuda l\'opció Enrere per deixar de fixar aquesta pantalla."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"S\'ha fixat l\'aplicació. En aquest dispositiu no es permet anul·lar-ne la fixació."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Pantalla fixada"</string>
@@ -1683,6 +1683,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Restableix ara"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> s\'ha desactivat"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conferència"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Descripció emergent"</string>
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 2c8f843..0bdd212 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1105,16 +1105,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Hlasitost médií"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Hlasitost oznámení"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Výchozí vyzváněcí tón"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Výchozí (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Žádný"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Vyzváněcí tóny"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Zvuky budíku"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Zvuky upozornění"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Neznámé"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="few">K dispozici jsou sítě Wi-Fi</item>
       <item quantity="many">K dispozici jsou sítě Wi-Fi</item>
@@ -1618,6 +1614,10 @@
     <string name="select_year" msgid="7952052866994196170">"Vyberte rok"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Číslice <xliff:g id="KEY">%1$s</xliff:g> byla smazána"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Pracovní <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Chcete-li tuto obrazovku uvolnit, klepněte na tlačítko Zpět a podržte jej."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Aplikace je připnutá: Odepnutí v tomto zařízení není povoleno."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Obrazovka připnuta"</string>
@@ -1755,6 +1755,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Resetovat"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – zakázáno"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferenční hovor"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Vyskakovací okno s popiskem"</string>
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 20b859c..f80f5f0 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"Vælg år"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> er slettet"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> – arbejde"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Hvis du vil frigøre dette skærmbillede, skal du trykke på Tilbage og holde fingeren nede."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Appen er fastgjort: Det er ikke tilladt at frigøre den på denne enhed."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Skærmen blev fastgjort"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index fcad7c2..1ceb0cc 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"Jahr auswählen"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> gelöscht"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (geschäftlich)"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Um die Fixierung dieses Bildschirms aufzuheben, \"Zurück\" berühren und halten."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Die App ist fixiert. Das Aufheben der Fixierung ist auf diesem Gerät nicht zulässig."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Bildschirm fixiert"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 2117233..b9d9503 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Ένταση ήχου πολυμέσων"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Ένταση ήχου ειδοποιήσεων"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Προεπιλεγμένος ήχος κλήσης"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Προεπιλογή (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Κανένας"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Ήχοι κλήσης"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Ήχοι ξυπνητηριού"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Ήχοι ειδοποίησης"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Άγνωστο"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Υπάρχουν διαθέσιμα δίκτυα Wi-Fi</item>
       <item quantity="one">Υπάρχει διαθέσιμο δίκτυο Wi-Fi</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Επιλογή έτους"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> διαγράφηκε"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Εργασία <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Για να ξεκαρφιτσώσετε αυτήν την οθόνη, αγγίξτε παρατεταμένα \"Επιστροφή\"."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Η εφαρμογή καρφιτσώθηκε: Το ξεκαρφίτσωμα δεν επιτρέπεται σε αυτήν τη συσκευή."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Η οθόνη καρφιτσώθηκε"</string>
@@ -1683,6 +1683,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>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Αναδυόμενο παράθυρο επεξήγησης εργαλείου"</string>
 </resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 47be8cf..5bc43e0 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Media volume"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Notification volume"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Default ringtone"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Default (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"None"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringtones"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarm Sounds"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Notification Sounds"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Unknown"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Wi-Fi networks available</item>
       <item quantity="one">Wi-Fi network available</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Select year"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> deleted"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"To unpin this screen, touch &amp; hold Back."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"App is pinned: unpinning isn\'t allowed on this device."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Screen pinned"</string>
@@ -1683,6 +1683,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Reset now"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Disabled <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conference Call"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Tooltip Pop-up"</string>
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 47be8cf..5bc43e0 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Media volume"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Notification volume"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Default ringtone"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Default (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"None"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringtones"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarm Sounds"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Notification Sounds"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Unknown"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Wi-Fi networks available</item>
       <item quantity="one">Wi-Fi network available</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Select year"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> deleted"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"To unpin this screen, touch &amp; hold Back."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"App is pinned: unpinning isn\'t allowed on this device."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Screen pinned"</string>
@@ -1683,6 +1683,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Reset now"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Disabled <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conference Call"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Tooltip Pop-up"</string>
 </resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 47be8cf..5bc43e0 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Media volume"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Notification volume"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Default ringtone"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Default (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"None"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringtones"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarm Sounds"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Notification Sounds"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Unknown"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Wi-Fi networks available</item>
       <item quantity="one">Wi-Fi network available</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Select year"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> deleted"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"To unpin this screen, touch &amp; hold Back."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"App is pinned: unpinning isn\'t allowed on this device."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Screen pinned"</string>
@@ -1683,6 +1683,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Reset now"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Disabled <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conference Call"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Tooltip Pop-up"</string>
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 50c4a67..cd2c5aa 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Volumen de los medios"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volumen de notificación"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Tono predeterminado"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Predeterminado (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Ninguno"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Tonos de llamada"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sonidos de la alarma"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sonidos de notificaciones"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Desconocido"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">redes de Wi-Fi disponibles</item>
       <item quantity="one">red de Wi-Fi disponible</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Seleccionar año"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> borrado"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Para dejar de fijar esta pantalla, mantén presionado Atrás."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"La aplicación está fijada, no se puede anular la fijación en este dispositivo."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Pantalla fija"</string>
@@ -1683,6 +1683,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Restablecer ahora"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Se inhabilitó <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conferencia"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Ventana emergente de la información sobre la herramienta"</string>
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index a91fc1c..fe7d1ac 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Volumen multimedia"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volumen de notificaciones"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Tono por defecto"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Predeterminado (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Ninguno"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Tonos"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sonidos de la alarma"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sonidos de notificaciones"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Desconocido"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Redes Wi-Fi disponibles</item>
       <item quantity="one">Red Wi-Fi disponible</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Seleccionar año"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> eliminado"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Mantén pulsado el botón Atrás para dejar de fijar esta pantalla."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"La aplicación está fijada: no se puede deshacer la fijación en este dispositivo."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Pantalla fijada"</string>
@@ -1683,6 +1683,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Restablecer ahora"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> inhabilitado"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conferencia"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Descripción emergente"</string>
 </resources>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index dc926d4..09668cb 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -650,7 +650,7 @@
     <string name="relationTypeMother" msgid="4578571352962758304">"Ema"</string>
     <string name="relationTypeParent" msgid="4755635567562925226">"Vanem"</string>
     <string name="relationTypePartner" msgid="7266490285120262781">"Partner"</string>
-    <string name="relationTypeReferredBy" msgid="101573059844135524">"Viitas:"</string>
+    <string name="relationTypeReferredBy" msgid="101573059844135524">"Soovitaja"</string>
     <string name="relationTypeRelative" msgid="1799819930085610271">"Sugulane"</string>
     <string name="relationTypeSister" msgid="1735983554479076481">"Õde"</string>
     <string name="relationTypeSpouse" msgid="394136939428698117">"Abikaasa"</string>
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"Aasta valimine"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> on kustutatud"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Töö <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Ekraani vabastamiseks puudutage pikalt nuppu Tagasi."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Rakendus on kinnitatud: vabastamine pole selles seadmes lubatud."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ekraan on kinnitatud"</string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index 190d61b..2ea4bed 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Euskarriaren bolumena"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Jakinarazpenen bolumena"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Tonu lehenetsia"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Lehenetsia (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Bat ere ez"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Tonuak"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarma-soinuak"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Jakinarazpen-soinuak"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Ezezaguna"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Wi-Fi sareak erabilgarri</item>
       <item quantity="one">Wi-Fi sarea erabilgarri</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Hautatu urtea"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> ezabatu da"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Laneko <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Pantailari aingura kentzeko, eduki sakatuta Atzera botoia."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Aplikazioa ainguratuta dago. Gailu honetan ezin da aingura kendu."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Pantaila ainguratu da"</string>
@@ -1683,6 +1683,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Berrezarri"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> desgaituta dago"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferentzia-deia"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Aholkudun leiho gainerakorra"</string>
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index d1d120f..55e67bc 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"انتخاب سال"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> حذف شد"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> محل کار"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"برای برداشتن پین این صفحه، «برگشت» را لمس کنید و نگه‌ دارید."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"برنامه پین شده است: برداشتن پین در این دستگاه مجاز نیست."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"صفحه پین شد"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 425b235..6800fa8 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Median äänenvoimakkuus"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Ilmoituksen äänenvoimakkuus"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Oletussoittoääni"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Oletus (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Ei mitään"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Soittoäänet"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Hälytysäänet"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Ilmoitusäänet"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Tuntematon"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Wi-Fi-verkkoja käytettävissä</item>
       <item quantity="one">Wi-Fi-verkko käytettävissä</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Valitse vuosi"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> poistettiin"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (työ)"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Irrota näyttö koskettamalla Takaisin-painiketta pitkään."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Sovellus on kiinnitetty. Irrottaminen ei ole sallittua tällä laitteella."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Näyttö kiinnitetty"</string>
@@ -1683,6 +1683,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Palauta nyt"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> ei ole käytössä."</string>
     <string name="conference_call" msgid="3751093130790472426">"Puhelinneuvottelu"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Työkaluvinkki ponnahdusikkunassa"</string>
 </resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 4ba4871..009b9eb 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"Sélectionnez une année"</string>
     <string name="deleted_key" msgid="7659477886625566590">"« <xliff:g id="KEY">%1$s</xliff:g> » a été supprimé"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (travail)"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Pour annuler l\'épinglage de cet écran, maintenez enfoncée la touche Retour."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"L\'application est épinglée : l\'annulation de l\'épinglage n\'est pas autorisée sur cet appareil."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Écran épinglé"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 3dc8b28..5b21dd4 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"Sélectionner une année"</string>
     <string name="deleted_key" msgid="7659477886625566590">"\"<xliff:g id="KEY">%1$s</xliff:g>\" supprimé"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (travail)"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Pour annuler l\'épinglage, appuyez de manière prolongée sur \"Retour\"."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"L\'application est épinglée. L\'annulation de l\'épinglage n\'est pas autorisée sur cet appareil."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Écran épinglé."</string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 077f4e0..10a7647 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Volume dos elementos multimedia"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume das notificacións"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Ton de chamada predeterminado"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Predeterminado (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Ningún"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Tons de chamada"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sons de alarma"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sons de notificación"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Descoñecido"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Redes wifi dispoñibles</item>
       <item quantity="one">Rede wifi dispoñible</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Seleccionar ano"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> eliminado"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> do traballo"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Para soltar a pantalla, mantén premido Volver."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"A aplicación está fixada: non se permite soltala neste dispositivo."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Pantalla fixada"</string>
@@ -1683,6 +1683,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Restablecer agora"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Desactivouse <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conferencia telefónica"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Ventá emerxente do cadro de información"</string>
 </resources>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index 149e466..9a7d432 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"મીડિયા વોલ્યુમ"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"સૂચના વૉલ્યૂમ"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"ડિફોલ્ટ રિંગટોન"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"ડિફૉલ્ટ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"કોઈ નહીં"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"રિંગટોન્સ"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"એલાર્મ ધ્વનિઓ"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"સૂચના ધ્વનિઓ"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"અજાણી"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">Wi-Fi નેટવર્ક્સ ઉપલબ્ધ</item>
       <item quantity="other">Wi-Fi નેટવર્ક્સ ઉપલબ્ધ</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"વર્ષ પસંદ કરો"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> કાઢી નાખી"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"કાર્યાલય <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"આ સ્ક્રીનને અનપિન કરવા માટે, પાછળને ટચ કરીને પકડી રાખો."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"ઍપ્લિકેશન પિન કરેલ છે. આ ઉપકરણ પર અનપિન કરવાની મંજૂરી નથી."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"સ્ક્રીન પિન કરી"</string>
@@ -1683,6 +1683,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>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"ટૂલટિપ પોપઅપ"</string>
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index c006df9..c46102b 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"वर्ष चुनें"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> को हटा दिया गया"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"कार्यस्थल का <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"इस स्क्रीन को अनपिन करने के लिए, वापस जाएं को स्पर्श करके रखें."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"ऐप पिन किया गया है: इस डिवाइस पर अनपिन करने की अनुमति नहीं है."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"स्‍क्रीन पिन की गई"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 8d90eb92..fa593acd 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1082,16 +1082,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Glasnoća medija"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Glasnoća obavijesti"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Zadana melodija zvona"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Zadano (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Ništa"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Melodije zvona"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Zvukovi alarma"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Zvukovi obavijesti"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Nepoznato"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">Dostupne su Wi-Fi mreže</item>
       <item quantity="few">Dostupne su Wi-Fi mreže</item>
@@ -1591,6 +1587,10 @@
     <string name="select_year" msgid="7952052866994196170">"Odaberite godinu"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Izbrisan je broj <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> za posao"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Da biste otkvačili ovaj zaslon, dodirnite i zadržite Natrag."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Aplikacija je prikvačena: otkvačivanje nije dopušteno na tom uređaju."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Zaslon je pričvršćen"</string>
@@ -1719,6 +1719,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Vrati na zadano sada"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – onemogućeno"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferencijski poziv"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Skočni prozor opisa"</string>
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 67e1c0f..d21e47e 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Média hangereje"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Értesítés hangereje"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Alapértelmezett csengőhang"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Alapértelmezett (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Egyik sem"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Csengőhangok"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Ébresztőhangok"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Értesítőhangok"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Ismeretlen"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Wi-Fi hálózatok érhetők el</item>
       <item quantity="one">Van elérhető Wi-Fi hálózat</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Válassza ki az évet"</string>
     <string name="deleted_key" msgid="7659477886625566590">"A(z) <xliff:g id="KEY">%1$s</xliff:g> érték törölve"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Munkahelyi <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"A képernyő rögzítésének feloldásához tartsa lenyomva a Vissza lehetőséget."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Az alkalmazás rögzítve van: a rögzítés feloldása nem engedélyezett ezen az eszközön."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Képernyő rögzítve"</string>
@@ -1683,6 +1683,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Visszaállítás most"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"A(z) <xliff:g id="LABEL">%1$s</xliff:g> letiltva"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferenciahívás"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Elemleíró előugró ablak"</string>
 </resources>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 6444b51..10072a2 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"Ընտրեք տարին"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> թիվը ջնջված է"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Աշխատանքային <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Այս էկրանն ապամրացնելու համար հպեք և պահեք Հետ կոճակը:"</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Հավելվածն ամրացված է: Ապամրացումն այս սարքում չի թույլատրվում:"</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Էկրանն ամրացված է"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 873e3ae..29d820e 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Volume media"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume pemberitahuan"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Nada dering default"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Default (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Tidak Ada"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Nada dering"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Suara alarm"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Suara notifikasi"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Tidak diketahui"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Jaringan Wi-Fi tersedia</item>
       <item quantity="one">Jaringan Wi-Fi tersedia</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Pilih tahun"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> dihapus"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Kantor <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Untuk melepas pin layar ini, sentuh &amp; tahan tombol Kembali."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Pin dipasang ke aplikasi. Melepas pin tidak diizinkan di perangkat ini."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Layar disematkan"</string>
@@ -1683,6 +1683,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Setel ulang sekarang"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> dinonaktifkan"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferensi Telepon"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Munculan Keterangan Alat"</string>
 </resources>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 70a41be..655c521 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Hljóðstyrkur efnisspilunar"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Hljóðstyrkur tilkynninga"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Sjálfgefinn hringitónn"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Sjálfgefið (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Ekkert"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Hringitónar"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Vekjarahljóð"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Tilkynningarhljóð"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Óþekkt"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">Wi-Fi net í boði</item>
       <item quantity="other">Wi-Fi net í boði</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Veldu ár"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> eytt"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> í vinnu"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Til að taka lásinn af þessari skjámynd skaltu halda inni bakkhnappinum."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Forritið er fest: Ekki er hægt að losa forrit í þessu tæki."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Skjár festur"</string>
@@ -1683,6 +1683,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Endurstilla núna"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Slökkt <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Símafundur"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Ábendingarsprettigluggi"</string>
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index b3521ff..446e367 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Volume contenuti multimediali"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume notifiche"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Suoneria predefinita"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Predefinita (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Nessuna"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Suonerie"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Suoni delle sveglie"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Suoni di notifica"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Sconosciuta"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Reti Wi-Fi disponibili</item>
       <item quantity="one">Rete Wi-Fi disponibile</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Seleziona anno"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> eliminato"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> lavoro"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Per sbloccare questa schermata tieni premuta l\'opzione Indietro."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"L\'app è bloccata. Su questo dispositivo non è consentito lo sblocco."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Schermata bloccata"</string>
@@ -1683,6 +1683,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Ripristina ora"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Widget <xliff:g id="LABEL">%1$s</xliff:g> disattivato"</string>
     <string name="conference_call" msgid="3751093130790472426">"Audioconferenza"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Popup descrizione comando"</string>
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index dd41f23..1881ae4 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1618,6 +1618,10 @@
     <string name="select_year" msgid="7952052866994196170">"בחר שנה"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> נמחק"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"עבודה <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"כדי לבטל את הצמדת המסך הזה, לחץ לחיצה ממושכת על הלחצן \'הקודם\'."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"האפליקציה מוצמדת: ביטול ההצמדה אסור במכשיר הזה."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"המסך מוצמד"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 28db181..fdfb890 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"年を選択"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g>を削除しました"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"仕事の<xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"この画面の固定を解除するには [戻る] を押し続けます。"</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"アプリは固定されています。この端末では固定を解除できません。"</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"画面を固定しました"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index c58803d..56f0a62 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"მედიის ხმა"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"შეტყობინების ხმა"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"ნაგულისხმევი ზარი"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"ნაგულისხმევი (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"არც ერთი"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"ზარები"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"მაღვიძარას ხმები"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"შეტყობინების ხმები"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"უცნობი"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">ხელმისაწვდომია Wi-Fi ქსელები</item>
       <item quantity="one">ხელმისაწვდომია Wi-Fi ქსელი</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"აირჩიეთ წელი"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> წაიშალა"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"სამსახური <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"ამ ეკრანის ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ ღილაკს „უკან“."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"აპი მიმაგრებულია: მიმაგრების მოხსნა არ არის ნებადართული ამ მოწყობილობაზე."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"ეკრანი დაფიქსირდა"</string>
@@ -1683,6 +1683,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>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"მინიშნების კონტექსტური სარკმელი"</string>
 </resources>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index a62cbf0..51d1dcc 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"Жыл таңдау"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> жойылды"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Жұмыс <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Осы экранды босату үшін \"Артқа\" түймесін басып тұрыңыз."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Бағдарлама белгіленді: Бұл құрылғыда белгіні алуға рұқсат берілмейді."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Экран түйрелді"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 08cac8c..aa6cb77 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -1566,6 +1566,10 @@
     <string name="select_year" msgid="7952052866994196170">"ជ្រើស​ឆ្នាំ"</string>
     <string name="deleted_key" msgid="7659477886625566590">"បាន​លុប <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"កន្លែង​ធ្វើការ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"ដើម្បីផ្តាច់អេក្រង់នេះ សូមប៉ះ និងសង្កត់ប៊ូតុងថយក្រោយឲ្យជាប់។"</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"កម្មវិធីនេះត្រូវបានខ្ទាស់។ មិនអនុញ្ញាតឲ្យដោះការខ្ទាស់នៅលើឧបករណ៍នេះទេ។"</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"បាន​ភ្ជាប់​អេក្រង់"</string>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index ab9cd90e..30d7e4e0 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"ವರ್ಷವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> ಅಳಿಸಲಾಗಿದೆ"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"ಕೆಲಸ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"ಈ ಪರದೆಯನ್ನು ಅನ್‌ಪಿನ್ ಮಾಡಲು, ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹಿಂಂದೆ ಒತ್ತಿ ಹಿಡಿಯಿರಿ."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"ಅಪ್ಲಿಕೇಶನ್ ಪಿನ್‌ ಮಾಡಲಾಗಿದೆ: ಈ ಸಾಧನದಲ್ಲಿ ಅನ್‌ಪಿನ್‌ ಮಾಡುವುದನ್ನು ಅನುಮತಿಸಲಾಗುವುದಿಲ್ಲ."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"ಸ್ಕ್ರೀನ್‌ ಪಿನ್‌ ಮಾಡಲಾಗಿದೆ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 10bb801..dbb14890 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"연도 선택"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> 삭제됨"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"업무용 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"이 화면을 고정 해제하려면 \'뒤로\'를 길게 터치합니다."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"앱이 고정되었습니다. 이 기기에서는 고정 해제를 허용하지 않습니다."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"화면 고정됨"</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 0d8a38e..3583189 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Медиа үнүнүн деңгээли"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Эскертме үнүнүн деңгээли"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Демейки рингтон"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Демейки рингтон (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Эч бир"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Ринтондор"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Ойготкучтун добуштары"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Эскертменин добуштары"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Белгисиз"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Wi-Fi тармагы жеткиликтүү</item>
       <item quantity="one">Wi-Fi тармагы жеткиликтүү</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Жылды тандаңыз"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> өчүрүлдү"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Жумуш <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Бул экранды бошотуу үчүн \"Артка\" баскычын басып, кармап туруңуз."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Колдонмо кадалган: Бул түзмөктө бошотууга уруксат жок."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Экран кадалды"</string>
@@ -1683,6 +1683,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>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Калкып чыгуучу кеңеш"</string>
 </resources>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index ab1a468..baf6d51 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"ເລືອກ​ປີ"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> ຖືກລຶບແລ້ວ"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"​ບ່ອນ​ເຮັດ​ວຽກ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"ກົດປຸ່ມກັບຄືນຄ້າງໄວ້ເພື່ອເຊົາປັກໝຸດໜ້າຈໍນີ້."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"ແອັບ​ຖືກ​ປັກ​ໝຸດ​ແລ້ວ: ບໍ່​ອະ​ນຸ​ຍາດ​ໃຫ້​ຖອນ​ປັກ​ໝຸດ​ຢູ່​ເທິງ​ອຸ​ປະ​ກອນ​ນີ້."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"​ປັກ​ໝຸດ​ໜ້າ​ຈໍ​ແລ້ວ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 4557264..f9293c4 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1618,6 +1618,10 @@
     <string name="select_year" msgid="7952052866994196170">"Pasirinkite metus"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Ištrinta: <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Darbo <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Kad atsegtumėte šį ekraną, palieskite ir palaikykite „Atgal“."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Programa prisegta: šiame įrenginyje negalima atsegti."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ekrano prisegtas"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 0965cf6..04ea14e 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1591,6 +1591,10 @@
     <string name="select_year" msgid="7952052866994196170">"Atlasiet gadu."</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> tika dzēsts."</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Darbā: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Lai atspraustu šo ekrānu, pieskarieties pogai “Atpakaļ” un turiet to."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Lietotne ir piesprausta. Atspraušana šajā ierīcē nav atļauta."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ekrāns ir piesprausts"</string>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index 8d96f5c7..aeb0c41 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Јачина на звук на медиуми"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Јачина на звук на известување"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Стандардна мелодија"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Стандардна (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Ниедна"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Мелодии"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Звуци за аларм"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Звуци за известување"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Непозната"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">Wi-Fi мрежи се достапни</item>
       <item quantity="other">Wi-Fi мрежи се достапни</item>
@@ -1566,6 +1562,10 @@
     <string name="select_year" msgid="7952052866994196170">"Избери година"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Избришано <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Работа <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"За откачување на екранов, допрете и задржете Назад."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Апликацијата е закачена: откачување не е дозволено на уредов."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Екранот е закачен"</string>
@@ -1685,6 +1685,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>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Појавен прозорец на совет за алатка"</string>
 </resources>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index 446d4f2..4193079 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"വർഷം തിരഞ്ഞെടുക്കുക"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> ഇല്ലാതാക്കി"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"ഔദ്യോഗികം <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"ഈ സ്‌ക്രീൻ അൺപിൻ ചെയ്യാൻ, ബാക്ക് ബട്ടൺ സ്‌പർശിച്ച് പിടിക്കുക"</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"അപ്ലിക്കേഷൻ പിൻ ചെയ്‌തു: ഈ ഉപകരണത്തിൽ അൺപിൻ ചെയ്യാനാവില്ല."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"സ്ക്രീൻ പിൻ ചെയ്തു"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 6199727..74006da 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"Жилийг сонгоно уу"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> устсан"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Ажлын <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Энэ дэлгэцийг эхэнд нээхийг болиулахын тулд Буцах товчлуурыг дараад, хүлээнэ үү."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"App-ыг тусгайлан тэмдэглэсэн байна: Энэ төхөөрөмж дээр тусгайлан тэмдэглэсэн сонголтыг устгах боломжгүй."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Дэлгэцийг тогтоосон"</string>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 8f2fc0f..dd99f15 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"मीडिया व्हॉल्यूम"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"सूचना व्हॉल्यूम"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"डीफॉल्ट रिंगटोन"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"डीफॉल्ट (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"काहीही नाही"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"रिंगटोन"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"अलार्म ध्वनी"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"सूचना ध्वनी"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"अज्ञात"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">वाय-फाय नेटवर्क उपलब्ध</item>
       <item quantity="other">वाय-फाय नेटवर्क उपलब्ध</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"वर्ष निवडा"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> हटविली"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"ही स्क्रीन अनपिन करण्यासाठी, परत ला स्पर्श करा आणि धरून ठेवा."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"अॅप पिन केलेला आहे: या डिव्हाइसवर अनपिन करण्यास अनुमती नाही."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"स्क्रीन पिन केली"</string>
@@ -1683,6 +1683,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>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"टूलटिप पॉपअप"</string>
 </resources>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 9b6a20a8..57edab8 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"Pilih tahun"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> dipadamkan"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Kerja <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Untuk menyahsematkan skrin ni, ketik &amp; tahan Kembali."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Apl disemat: Nyahsemat tidak dibenarkan pada peranti ini."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Skrin disemat"</string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 3276dcd..834a665 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"မီဒီယာအသံအတိုးအကျယ်"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"အကြောင်းကြားသံအတိုးအကျယ်"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"မူရင်းမြည်သံ"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"မူရင်း (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"တစ်ခုမှမဟုတ်"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"မြည်သံများ"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"နှိုးစက်သံ"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"အကြောင်းကြားချက်အသံ"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"အမျိုးအမည်မသိ"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Wi-Fi ကွန်ယက်များရရှိနိုင်သည်</item>
       <item quantity="one">Wi-Fi ကွန်ယက်ရရှိနိုင်သည်</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"ခုနှစ်ကို ရွေးပါ"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> ကို ဖျက်ပြီးပါပြီ"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"အလုပ် <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"ဤမျက်နှာပြင်ကို ပင်ဖြုတ်ရန် \"နောက်သို့\" ကိုထိပြီးဖိထားပါ။"</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"အက်ပ်ကို ပင်ထိုးထားသည်။ ပင်ဖျက်ခြင်းကို ဒီစက်မှာ မရနိုင်ပါ။"</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"မျက်နှာပြင်ကို ပင်ထိုးထား"</string>
@@ -1683,6 +1683,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>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"အကြံပြုချက်ပြ ပေါ့အပ်ဝင်းဒိုး"</string>
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index dba56dc..61e74a2 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Medievolum"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Varslingsvolum"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Standard ringetone"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Standard (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Ingen"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringelyder"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarmlyder"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Varsellyder"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Ukjent"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Wi-Fi-nettverk er tilgjengelig</item>
       <item quantity="one">Wi-Fi-nettverk er tilgjengelig</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Velg året"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> er slettet"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Jobb-<xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"For å løsne denne skjermen, trykk og hold inne Tilbake."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Appen er festet – du kan ikke løsne apper på denne enheten."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Skjermen er festet"</string>
@@ -1683,6 +1683,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Tilbakestill nå"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> er slått av"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferansesamtale"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Verktøytips i forgrunnen"</string>
 </resources>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 27abf1a..d6c8612 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -1065,16 +1065,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"मिडियाको मात्रा"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"सूचना भोल्युम"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"पूर्वनिर्धारित रिङटोन"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"पूर्वनिर्धारित (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"कुनै पनि होइन"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"रिङटोनहरू"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"अलार्मका आवाजहरू"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"सूचना सम्बन्धी आवाजहरू"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"अज्ञात"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Wi-Fi सञ्जालहरू उपलब्ध छन्</item>
       <item quantity="one">Wi-Fi सञ्जाल उपलब्ध छ</item>
@@ -1570,6 +1566,10 @@
     <string name="select_year" msgid="7952052866994196170">"वर्ष चयन गर्नुहोस्"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> हटाइयो"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"यस स्क्रिनलाई अनपिन गर्न पछाडि बटनलाई छोइराख्नुहोस्।"</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"अनुप्रयोग पिन गरियो: यस यन्त्रमा अनपिन गर्ने अनुमति छैन।"</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"स्क्रिन पिन गरियो"</string>
@@ -1689,6 +1689,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>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"उपकरणको वर्णन गर्ने पपअप"</string>
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index b02c9e1..f7c76cd 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Mediavolume"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Meldingsvolume"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Standaardbeltoon"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Standaard (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Geen"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Beltonen"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarmgeluiden"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Meldingsgeluiden"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Onbekend"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Wifi-netwerken beschikbaar</item>
       <item quantity="one">Wifi-netwerk beschikbaar</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Jaar selecteren"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> verwijderd"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Werk <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Tik op Terug en houd vast om dit scherm los te maken."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"App is vastgezet: losmaken is niet toegestaan op dit apparaat."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Scherm vastgezet"</string>
@@ -1683,6 +1683,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Nu resetten"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> uitgeschakeld"</string>
     <string name="conference_call" msgid="3751093130790472426">"Telefonische vergadering"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Pop-up met knopinfo"</string>
 </resources>
diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
index cb63a54..39c5dfa 100644
--- a/core/res/res/values-pa-rIN/strings.xml
+++ b/core/res/res/values-pa-rIN/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"ਸਾਲ ਚੁਣੋ"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> ਹਟਾਇਆ ਗਿਆ"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"ਕੰਮ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"ਇਸ ਸਕ੍ਰੀਨ ਨੂੰ ਅਨਪਿੰਨ ਕਰਨ ਲਈ, ਸਪਰਸ਼ ਕਰੋ &amp; ਦਬਾਈ ਰੱਖੋ।"</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"ਐਪ ਪਿੰਨਡ ਹੈ: ਇਸ ਡੀਵਾਈਸ ਤੇ ਅਨਪਿਨ ਕਰਨ ਦੀ ਆਗਿਆ ਨਹੀਂ ਹੈ।"</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"ਸਕ੍ਰੀਨ ਪਿੰਨ ਕੀਤੀ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 3cfb242..4ffd963 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1105,16 +1105,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Głośność multimediów"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Głośność powiadomień"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Dzwonek domyślny"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Domyślny (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Brak"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Dzwonki"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Dźwięki alarmu"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Dźwięki powiadomień"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Nieznany"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="few">Dostępne są sieci Wi-Fi</item>
       <item quantity="many">Dostępne są sieci Wi-Fi</item>
@@ -1618,6 +1614,10 @@
     <string name="select_year" msgid="7952052866994196170">"Wybierz rok"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> usunięte"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (praca)"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Aby odpiąć ten ekran, naciśnij i przytrzymaj Wstecz."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Aplikacja jest przypięta. Nie możesz jej odpiąć na tym urządzeniu."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ekran przypięty"</string>
@@ -1755,6 +1755,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Resetuj teraz"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Wyłączono: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Połączenie konferencyjne"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Wyskakujące okno z etykietką"</string>
 </resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index b5b30a8..482c1e9 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Volume da mídia"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume da notificação"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Toque padrão"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Padrão (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Nenhum"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Toques"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sons do alarme"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sons de notificação"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Desconhecido"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">Redes Wi-Fi disponíveis</item>
       <item quantity="other">Redes Wi-Fi disponíveis</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Selecione o ano"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> excluído"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Trabalho: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Para liberar esta tela, toque no botão \"Voltar\" e mantenha-o pressionado."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"O app está fixado. A liberação não é permitida neste dispositivo."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Tela fixada"</string>
@@ -1683,6 +1683,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Reiniciar agora"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Widget <xliff:g id="LABEL">%1$s</xliff:g> desativado"</string>
     <string name="conference_call" msgid="3751093130790472426">"Teleconferência"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Pop-up de dica"</string>
 </resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 952df71..3f9417e 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Volume de multimédia"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume de notificações"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Toque predefinido"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Predefinição (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Nada"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Toques"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sons de alarme"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sons de notificação"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Desconhecido"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Redes Wi-Fi disponíveis</item>
       <item quantity="one">Rede Wi-Fi disponível</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Selecionar ano"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> eliminado"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de trabalho"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Para soltar este ecrã, toque sem soltar em Anterior."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"A aplicação está fixa: não é permitido soltá-la neste dispositivo."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ecrã fixo"</string>
@@ -1683,6 +1683,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Repor agora"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> desativado"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conferência"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Pop-up de sugestão"</string>
 </resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index b5b30a8..482c1e9 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Volume da mídia"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume da notificação"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Toque padrão"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Padrão (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Nenhum"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Toques"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sons do alarme"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sons de notificação"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Desconhecido"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">Redes Wi-Fi disponíveis</item>
       <item quantity="other">Redes Wi-Fi disponíveis</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Selecione o ano"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> excluído"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Trabalho: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Para liberar esta tela, toque no botão \"Voltar\" e mantenha-o pressionado."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"O app está fixado. A liberação não é permitida neste dispositivo."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Tela fixada"</string>
@@ -1683,6 +1683,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Reiniciar agora"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Widget <xliff:g id="LABEL">%1$s</xliff:g> desativado"</string>
     <string name="conference_call" msgid="3751093130790472426">"Teleconferência"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Pop-up de dica"</string>
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 6f938d9..5735f7c 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1591,6 +1591,10 @@
     <string name="select_year" msgid="7952052866994196170">"Selectați anul"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> a fost șters"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de serviciu"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Pentru a anula fixarea acestui ecran, atingeți lung opțiunea Înapoi."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Aplicația este fixată: Anularea fixării nu este permisă pe acest dispozitiv."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ecran fixat"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 83ae58b..0d6ca06 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1105,16 +1105,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Громкость мультимедиа"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Громкость уведомлений"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Мелодия по умолчанию"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"По умолчанию (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Без звука"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Мелодии"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Сигнал будильника"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Мелодии уведомлений"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Неизвестно"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">Есть доступные сети Wi-Fi</item>
       <item quantity="few">Есть доступные сети Wi-Fi</item>
@@ -1618,6 +1614,10 @@
     <string name="select_year" msgid="7952052866994196170">"Выберите год"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Цифра <xliff:g id="KEY">%1$s</xliff:g> удалена"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Рабочий <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Чтобы открепить экран, нажмите и удерживайте кнопку \"Назад\"."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Включена блокировка в приложении. Ее отключение запрещено правилами организации."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Блокировка включена"</string>
@@ -1755,6 +1755,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>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Подсказка"</string>
 </resources>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 2a4ee66..7526c1e 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -108,7 +108,7 @@
     <string name="serviceClassDataSync" msgid="7530000519646054776">"සමමුහුර්ත කිරීම"</string>
     <string name="serviceClassPacket" msgid="6991006557993423453">"පැකැට්ටුව"</string>
     <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
-    <string name="roamingText0" msgid="7170335472198694945">"රෝමිං දර්ශකය සක්‍රියයි"</string>
+    <string name="roamingText0" msgid="7170335472198694945">"රෝමිං දර්ශකය ක්‍රියාත්මකයි"</string>
     <string name="roamingText1" msgid="5314861519752538922">"රෝමිං දර්ශකය අක්‍රියයි"</string>
     <string name="roamingText2" msgid="8969929049081268115">"රෝමිං දර්ශකය සැණෙලි වෙයි"</string>
     <string name="roamingText3" msgid="5148255027043943317">"වටපිටාවෙන් ඉවත්ව"</string>
@@ -189,7 +189,7 @@
     <string name="turn_on_radio" msgid="3912793092339962371">"නොරැහන් සක්‍රිය කරන්න"</string>
     <string name="turn_off_radio" msgid="8198784949987062346">"නොරැහැන් අක්‍රිය කරන්න"</string>
     <string name="screen_lock" msgid="799094655496098153">"තිර අගුල"</string>
-    <string name="power_off" msgid="4266614107412865048">"බලය අක්‍රිය කරන්න"</string>
+    <string name="power_off" msgid="4266614107412865048">"බල රහිත කරන්න"</string>
     <string name="silent_mode_silent" msgid="319298163018473078">"හඬ නඟනය අක්‍රියයි"</string>
     <string name="silent_mode_vibrate" msgid="7072043388581551395">"හඬ නඟනය කම්පනය"</string>
     <string name="silent_mode_ring" msgid="8592241816194074353">"හඬ නඟනය සක්‍රීයයි"</string>
@@ -213,7 +213,7 @@
     <string name="global_actions" product="tv" msgid="7240386462508182976">"රූපවාහිනී විකල්ප"</string>
     <string name="global_actions" product="default" msgid="2406416831541615258">"දුරකථන විකල්ප"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"තිර අගුල"</string>
-    <string name="global_action_power_off" msgid="4471879440839879722">"බලය අක්‍රිය කරන්න"</string>
+    <string name="global_action_power_off" msgid="4471879440839879722">"බල රහිත කරන්න"</string>
     <string name="global_action_emergency" msgid="7112311161137421166">"හදිසි"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"දෝෂ වර්තාව"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"දෝෂ වාර්තාවක් ගන්න"</string>
@@ -228,7 +228,7 @@
     </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"නිහඬ ආකාරය"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"ශබ්දය අක්‍රියයි"</string>
-    <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"හඬ සක්‍රියයි"</string>
+    <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"හඬ ක්‍රියාත්මකයි"</string>
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"අහස්යානා ආකාරය"</string>
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"අහස්යානා ආකාරය සක්‍රීයයි."</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"අහස්යානා අකාරය අක්‍රියයි"</string>
@@ -975,7 +975,7 @@
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"විවෘත කරන්න"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"සමඟ සංස්කරණය කරන්න"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s සමඟ සංස්කරණය කරන්න"</string>
-    <string name="whichEditApplicationLabel" msgid="7183524181625290300">"සංස්කරණය කරන්න"</string>
+    <string name="whichEditApplicationLabel" msgid="7183524181625290300">"සංස්කරණය"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"සමඟ බෙදාගන්න"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%s සමඟ බෙදාගන්න"</string>
     <string name="whichSendApplicationLabel" msgid="4579076294675975354">"බෙදා ගන්න"</string>
@@ -1104,7 +1104,7 @@
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"ඍජු Wi-Fi"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ඍජු Wi-Fi ආරම්භ කරන්න. මෙය Wi-Fi සේවාදායක/හොට්ස්පොට් එක අක්‍රිය කරනු ඇත."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"ඍජු Wi-Fi ආරම්භ කළ නොහැක."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi ඍජු සම්බන්ධතාව සක්‍රියයි"</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ක්‍රියාත්මකයි"</string>
     <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"සැකසීම් සඳහා තට්ටු කරන්න"</string>
     <string name="accept" msgid="1645267259272829559">"පිළිගන්න"</string>
     <string name="decline" msgid="2112225451706137894">"ප්‍රතික්ෂේප කරන්න"</string>
@@ -1336,7 +1336,7 @@
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB ධාවකය"</string>
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ධාවකය"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB ආචයනය"</string>
-    <string name="extract_edit_menu_button" msgid="8940478730496610137">"සංස්කරණය කරන්න"</string>
+    <string name="extract_edit_menu_button" msgid="8940478730496610137">"සංස්කරණය"</string>
     <string name="data_usage_warning_title" msgid="3620440638180218181">"දත්ත භාවිතය ගැන ඇඟවීම"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"භාවිතය සහ සැකසීම් බැලීමට තට්ටු කරන්න."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G දත්ත සීමාවට ළඟාවී ඇත"</string>
@@ -1382,7 +1382,7 @@
     <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"පද්ධතිය"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"බ්ලූටූත් ශ්‍රව්‍ය"</string>
-    <string name="wireless_display_route_description" msgid="9070346425023979651">"රැහැන් රහිත දර්ශනය"</string>
+    <string name="wireless_display_route_description" msgid="9070346425023979651">"නොරැහැන් සංදර්ශකය"</string>
     <string name="media_route_button_content_description" msgid="591703006349356016">"Cast"</string>
     <string name="media_route_chooser_title" msgid="1751618554539087622">"උපාංගයට සම්බන්ධ වන්න"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"තිරය උපාංගයට යොමු කරන්න"</string>
@@ -1566,6 +1566,10 @@
     <string name="select_year" msgid="7952052866994196170">"වසර තෝරන්න"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> මකා දමන ලදි"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"වැඩ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"මෙම තිරය ඇමුණුම් ඉවත් කිරීමට, ස්පර්ශ කර අල්ලා ගෙන සිටින්න."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"යෙදුම අමුණා ඇත: ගැලවීමට මෙම උපාංගය මත ඉඩ දිය නොහැකිය.‍"</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"තිරය අගුළු දමා ඇත"</string>
@@ -1614,7 +1618,7 @@
     </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>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"ඔබ මෙය ක්‍රියාවිරහිත කරන තුරු"</string>
     <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 ef7678c..7ff3ce2 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1105,16 +1105,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Hlasitosť médií"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Hlasitosť upozornení"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Predvolený tón zvonenia"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Predvolený (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Žiadny"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Tóny zvonenia"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Zvuky budíka"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Zvuky upozornení"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Neznáme"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="few">K dispozícii sú siete Wi-Fi</item>
       <item quantity="many">K dispozícii sú siete Wi-Fi</item>
@@ -1618,6 +1614,10 @@
     <string name="select_year" msgid="7952052866994196170">"Vyberte rok"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Číslo <xliff:g id="KEY">%1$s</xliff:g> bolo odstránené"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Práca – <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Ak chcete uvoľniť túto obrazovku, klepnite na tlačidlo Späť a podržte ho."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Aplikácia je pripnutá. Uvoľnenie nie je na tomto zariadení povolené."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Obrazovka bola pripnutá"</string>
@@ -1755,6 +1755,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Resetovať"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Deaktivovaná miniaplikácia <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferenčný hovor"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Kontextové okno s popisom"</string>
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index f3a2d23..f7b8096 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -656,7 +656,7 @@
     <string name="relationTypeMother" msgid="4578571352962758304">"Mati"</string>
     <string name="relationTypeParent" msgid="4755635567562925226">"Starši"</string>
     <string name="relationTypePartner" msgid="7266490285120262781">"Partner"</string>
-    <string name="relationTypeReferredBy" msgid="101573059844135524">"Predlagatelj:"</string>
+    <string name="relationTypeReferredBy" msgid="101573059844135524">"Predlagatelj"</string>
     <string name="relationTypeRelative" msgid="1799819930085610271">"Sorodnik"</string>
     <string name="relationTypeSister" msgid="1735983554479076481">"Sestra"</string>
     <string name="relationTypeSpouse" msgid="394136939428698117">"Zakonski partner"</string>
@@ -1618,6 +1618,10 @@
     <string name="select_year" msgid="7952052866994196170">"Izberite leto"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Številka <xliff:g id="KEY">%1$s</xliff:g> je izbrisana"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> za delo"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Če želite odpeti ta zaslon, se dotaknite tipke za nazaj in jo pridržite."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Aplikacija je pripeta: v tej napravi odpenjanje ni dovoljeno."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Zaslon je pripet"</string>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index 69f14d5..c3ccaca 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"Përzgjidh vitin"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> u fshi"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Puna <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Për të hequr gozhdimin e ekranit, prek dhe mbaj të shtypur \"Prapa\"."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Ekrani është i gozhduar. Anulimi i mbërthimit nuk lejohet nga organizata jote."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ekrani u gozhdua"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 881421c..da44a65 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1082,16 +1082,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Јачина звука медија"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Јачина звука обавештења"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Подразумевани звук звона"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Подразумевано (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Без звука"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Звукови звона"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Звуци аларма"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Звуци обавештења"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Непознато"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">Wi-Fi мреже су доступне</item>
       <item quantity="few">Wi-Fi мреже су доступне</item>
@@ -1591,6 +1587,10 @@
     <string name="select_year" msgid="7952052866994196170">"Изаберите годину"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Избрисали сте <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> на послу"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Да бисте откачили овај екран, додирните и задржите Назад."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Апликација је закачена: откачињање није дозвољено на овом уређају."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Екран је закачен"</string>
@@ -1719,6 +1719,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>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Искачуће објашњење"</string>
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index fdffd46..1bf5196 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Mediavolym"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Meddelandevolym"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Standardringsignal"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Standard (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Ingen"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringsignaler"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Ljud för alarm"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Aviseringsljud"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Okänt"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Wi-Fi-nätverk är tillgängliga</item>
       <item quantity="one">Wi-Fi-nätverk är tillgängligt</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Välj år"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> har tagits bort"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> för arbetet"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Om du vill lossa skärmen trycker du länge på Tillbaka."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Appen är fäst. Att lossa den är inte tillåtet på den här enheten."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Skärmen är fäst"</string>
@@ -1683,6 +1683,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Återställ nu"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> har inaktiverats"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferenssamtal"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Popup-fönster med beskrivning"</string>
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 500b33b..1d3c7ac 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1057,16 +1057,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Sauti ya midia"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Sauti ya arifa"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Mlio chaguo-msingi"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Chaguo-msingi (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Hamna"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Toni za mlio"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sauti za kengele"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sauti za arifa"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Haijulikani"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Mitandao ya Wi-Fi inapatikana</item>
       <item quantity="one">Mtandao wa Wi-Fi unapatikana</item>
@@ -1562,6 +1558,10 @@
     <string name="select_year" msgid="7952052866994196170">"Chagua mwaka"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> kimefutwa"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Ya kazini <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Ili kubandua skrini hii, gusa na ushikilie Nyuma."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Programu imebanwa: Kubanuliwa hakuruhusiwi kwenye kifaa hiki."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Skrini imebandikwa"</string>
@@ -1681,6 +1681,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Weka upya sasa"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> imezimwa"</string>
     <string name="conference_call" msgid="3751093130790472426">"Simu ya Kongamano"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Kidirisha Ibukizi cha vidokezo"</string>
 </resources>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index 131d03f..46a4589 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"ஆண்டைத் தேர்ந்தெடுக்கவும்"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> நீக்கப்பட்டது"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"பணியிடம் <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"இந்தத் திரையை விலக்க, \"முந்தையது\" பொத்தானைத் தொட்டுப் பிடிக்கவும்."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"பயன்பாடு பொருத்தப்பட்டது: பொருத்தியதை நீக்குவதற்கு இந்தச் சாதனத்தில் அனுமதியில்லை."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"திரை பின் செய்யப்பட்டது"</string>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 2d6b2ad..c6722ee 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"సంవత్సరాన్ని ఎంచుకోండి"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> తొలగించబడింది"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"కార్యాలయం <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"ఈ స్క్రీన్‌ని అన్‌పిన్ చేయడానికి, వెనుకకు తాకి &amp; అలాగే పట్టుకోండి."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"అనువర్తనం పిన్ చేయబడింది: ఈ పరికరంలో అన్‌పిన్ చేయడానికి అనుమతి లేదు."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"స్క్రీన్ పిన్ చేయబడింది"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index c6a8544..ab04bec 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"เลือกปี"</string>
     <string name="deleted_key" msgid="7659477886625566590">"ลบ <xliff:g id="KEY">%1$s</xliff:g> แล้ว"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g>ที่ทำงาน"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"หากต้องการเลิกตรึงหน้าจอนี้ แตะ \"กลับ\" ค้างไว้"</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"มีการตรึงแอป: ไม่อนุญาตให้เลิกตรึงบนอุปกรณ์นี้"</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"ตรึงหน้าจอแล้ว"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index abcb19a..e7cec56 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"Pumili ng taon"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Tinanggal ang <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> sa Trabaho"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Upang i-unpin ang screen na ito, pindutin nang matagal ang Bumalik."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Naka-pin ang app: Hindi pinapayagan ang pag-a-unpin sa device na ito."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Naka-pin ang screen"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 4550784..59dc68e 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"Yılı seçin"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> silindi"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (İş)"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Bu ekranın sabitlemesini kaldırmak için Geri\'ye dokunup basılı tutun."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Uygulama sabitlendi. Bu cihazda sabitlemenin kaldırılmasına izin verilmiyor."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ekran sabitlendi"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index b5561b9..0ac3b80 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1105,16 +1105,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Гучність медіа"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Гучність сповіщення"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Мелодія за умовчанням"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"За умовчанням (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Немає"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Мелодії"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Сигнали будильника"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Сигнали сповіщень"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Невідомо"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">Мережі Wi-Fi доступні</item>
       <item quantity="few">Мережі Wi-Fi доступні</item>
@@ -1618,6 +1614,10 @@
     <string name="select_year" msgid="7952052866994196170">"Виберіть рік"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> видалено"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Робоча <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Щоб відкріпити цей екран, натисніть і утримуйте кнопку \"Назад\"."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Додаток закріплено. Його не можна відкріпити на цьому пристрої."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Екран закріплено"</string>
@@ -1755,6 +1755,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>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Спливаюча підказка"</string>
 </resources>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index ecb6ee0..715dbed 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"سال منتخب کریں"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> کو حذف کر دیا گیا"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"دفتر <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"اس اسکرین سے پن ہٹانے کیلئے، پیچھے کو تھپتھپائیں اور دبا کر رکھیں۔"</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"ایپ کو پن کر دیا گیا ہے: اس آلہ پر پن ہٹانے کی اجازت نہیں ہے۔"</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"اسکرین کو پن کر دیا گیا"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index dd8b8ba..255982c 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Multimedia ovozi"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Eslatma tovushi"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Standart rington"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Standart (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Yo‘q"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringtonlar"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Signal ovozlari"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Bildirishnoma ovozlari"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Noma’lum"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Wi-Fi tarmoqlari aniqlandi</item>
       <item quantity="one">Wi-Fi tarmog‘i aniqlandi</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Yilni tanlash"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> raqami o‘chirib tashlandi"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Ish <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Bu ekrandan chiqish uchun “Orqaga” tugmasini bosib turing."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Ilova qadab qo‘yilgan. Uni ekrandan yechish ushbu qurilmada ta’qiqlangan."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ekran qadab qo‘yildi"</string>
@@ -1683,6 +1683,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Asl holatga qaytarish"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> vidjeti o‘chirilgan"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferens-aloqa"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Qalqib chiquvchi maslahat oynasi"</string>
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 37f1a9b..1f6a1cd 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"Chọn năm"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Đã xóa <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> làm việc"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Để bỏ ghim màn hình này, nhấn và giữ Quay lại."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Ứng dụng được ghim: Không được phép bỏ ghim trên thiết bị này."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Đã ghim màn hình"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 9def7db..5991f54 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"选择年份"</string>
     <string name="deleted_key" msgid="7659477886625566590">"已删除<xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"工作<xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"要取消固定此屏幕,请触摸并按住“返回”按钮。"</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"应用处于固定状态:在此设备上不允许退出该模式。"</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"已固定屏幕"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 6f101ab..7191a3d 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1240,7 +1240,7 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"桌布"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"變更桌布"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"通知接聽器"</string>
-    <string name="vr_listener_binding_label" msgid="4316591939343607306">"虛擬現實接聽器"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR 接聽器"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"條件供應商"</string>
     <string name="notification_ranker_binding_label" msgid="774540592299064747">"通知排序服務"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN 已啟用。"</string>
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"選取年份"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> 已刪除"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"公司<xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"如要取消固定這個畫面,請按住 [返回]。"</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"應用程式已固定:不允許在此裝置上取消固定。"</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"螢幕已固定"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 93acd0e..9e37672 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1564,6 +1564,10 @@
     <string name="select_year" msgid="7952052866994196170">"選取年份"</string>
     <string name="deleted_key" msgid="7659477886625566590">"已刪除 <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"公司<xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"如要取消固定這個畫面,請按住「返回」按鈕。"</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"應用程式已固定:無法在這部裝置取消固定。"</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"已固定螢幕"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 14ea738..66d1010 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1059,16 +1059,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Ivolumu yemidiya"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Ivolumu yesaziso"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Iringithoni emisiwe"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Okuzenzakalelayo (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Akunalutho"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Amaringithoni"</string>
-    <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (3914515995813061520) -->
-    <skip />
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Imisindo ye-alamu"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Imisindo yezaziso"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Akwaziwa"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">Amanethiwekhi we-Wi-Fi ayatholakala</item>
       <item quantity="other">Amanethiwekhi we-Wi-Fi ayatholakala</item>
@@ -1564,6 +1560,10 @@
     <string name="select_year" msgid="7952052866994196170">"Khetha unyaka"</string>
     <string name="deleted_key" msgid="7659477886625566590">"I-<xliff:g id="KEY">%1$s</xliff:g> isusiwe"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Umsebenzi <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+    <skip />
     <string name="lock_to_app_toast" msgid="1420543809500606964">"Ukuze ususe ukuphina lesi sikrini, thinta futhi ubambe okuthi Emuva."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Uhlelo lokusebenza luphiniwe: Ukususa ukuphina akuvunyelwe kule divayisi."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Isikrini siphiniwe"</string>
@@ -1683,6 +1683,5 @@
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Setha kabusha manje"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"I-<xliff:g id="LABEL">%1$s</xliff:g> ekhutshaziwe"</string>
     <string name="conference_call" msgid="3751093130790472426">"Ikholi yengqungquthela"</string>
-    <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
-    <skip />
+    <string name="tooltip_popup_title" msgid="8101791425834697618">"Okuzivelelayo kwe-tooltip"</string>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 95f372c..7045eaf 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2239,13 +2239,23 @@
             (black). -->
         <attr name="background" format="reference|color" />
 
-        <!-- Sets the padding, in pixels, of all four edges.  Padding is defined as
-             space between the edges of the view and the view's content. A views size
-             will include it's padding.  If a {@link android.R.attr#background}
+        <!-- Sets the padding, in pixels, of all four edges. Padding is defined as
+             space between the edges of the view and the view's content. This value will take
+             precedence over any of the edge-specific values, including
+             paddingHorizontal and paddingVertical, if set. A view's size
+             will include its padding. If a {@link android.R.attr#background}
              is provided, the padding will initially be set to that (0 if the
-             drawable does not have padding).  Explicitly setting a padding value
+             drawable does not have padding). Explicitly setting a padding value
              will override the corresponding padding found in the background. -->
         <attr name="padding" format="dimension" />
+        <!-- Sets the padding, in pixels, of the left and right edges; see
+             {@link android.R.attr#padding}. This value will take precedence over
+             paddingLeft, paddingRight, paddingStart, and paddingEnd, if set. -->
+        <attr name="paddingHorizontal" format="dimension" />
+        <!-- Sets the padding, in pixels, of the top and bottom edges; see
+             {@link android.R.attr#padding}. This value will take precedence over
+             paddingTop and paddingBottom, if set. -->
+        <attr name="paddingVertical" format="dimension" />
         <!-- Sets the padding, in pixels, of the left edge; see {@link android.R.attr#padding}. -->
         <attr name="paddingLeft" format="dimension" />
         <!-- Sets the padding, in pixels, of the top edge; see {@link android.R.attr#padding}. -->
@@ -3059,7 +3069,11 @@
         <attr name="layout_width" />
         <attr name="layout_height" />
         <!--  Specifies extra space on the left, top, right and bottom
-              sides of this view. This space is outside this view's bounds.
+              sides of this view.  If both layout_margin and any of layout_marginLeft,
+              layout_marginRight, layout_marginStart, layout_marginEnd,
+              layout_marginTop, and layout_marginBottom are
+              also specified, the layout_margin value will take precedence over the
+              edge-specific values. This space is outside this view's bounds.
               Margin values should be positive. -->
         <attr name="layout_margin" format="dimension"  />
         <!--  Specifies extra space on the left side of this view.
@@ -3086,6 +3100,29 @@
               This space is outside this view's bounds.
               Margin values should be positive.-->
         <attr name="layout_marginEnd" format="dimension"  />
+        <!--  Specifies extra space on the left and right sides of this view.
+              Specifying layout_marginHorizontal is equivalent to specifying
+              either layout_marginLeft and layout_marginRight or
+              layout_marginStart and layout_marginEnd with that same value.
+              If both layout_marginHorizontal and any of layout_marginLeft,
+              layout_marginRight, layout_marginStart, and layout_marginEnd are
+              also specified, the layout_marginHorizontal value will take precedence over the
+              edge-specific values. Also, layout_margin will always take precendent over
+              any of these values, including layout_marginHorizontal.
+              This space is outside this view's bounds.
+              Margin values should be positive.-->
+        <attr name="layout_marginHorizontal" format="dimension"  />
+        <!--  Specifies extra space on the tyop and bottom sides of this view.
+              Specifying layout_marginVertical is equivalent to specifying
+              layout_marginTop and layout_marginBottom with that same value.
+              If both layout_marginVertical and either/both layout_marginTop and
+              layout_marginBottom are also specified, the layout_marginVertical value
+              will take precedence over the edge-specific values.
+              Also, layout_margin will always take precendent over
+              any of these values, including layout_marginHorizontal.
+              This space is outside this view's bounds.
+              Margin values should be positive.-->
+        <attr name="layout_marginVertical" format="dimension"  />
     </declare-styleable>
 
     <!-- Use <code>input-method</code> as the root tag of the XML resource that
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 0995bc3..fa9cac2 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -165,6 +165,11 @@
     <color name="user_icon_default_gray">#ff9e9e9e</color><!-- gray 500 -->
     <color name="user_icon_default_white">#ffffffff</color><!-- white -->
 
+    <!-- Default profile badge colors -->
+    <color name="profile_badge_1">#ffff5722</color><!-- Orange -->
+    <color name="profile_badge_2">#ff000000</color><!-- Black -->
+    <color name="profile_badge_3">#ff22f033</color><!-- Green -->
+
     <!-- Multi-sim sim colors -->
     <color name="Teal_700">#ff00796b</color>
     <color name="Teal_800">#ff00695c</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a7c5b2a..d8ae138 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -422,6 +422,9 @@
     <!-- Boolean indicating whether Hotspot 2.0/Passpoint and ANQP queries is enabled -->
     <bool translatable="false" name="config_wifi_hotspot2_enabled">false</bool>
 
+    <!-- Boolean indicating whether 802.11r Fast BSS Transition is enabled on this platform -->
+    <bool translatable="false" name="config_wifi_fast_bss_transition_enabled">false</bool>
+
     <!-- Device type information conforming to Annex B format in WiFi Direct specification.
          The default represents a dual-mode smartphone -->
     <string translatable="false" name="config_wifi_p2p_device_type">10-0050F204-5</string>
@@ -1650,7 +1653,7 @@
     <bool name="config_actionMenuItemAllCaps">true</bool>
 
     <!-- Remote server that can provide NTP responses. -->
-    <string translatable="false" name="config_ntpServer">2.android.pool.ntp.org</string>
+    <string translatable="false" name="config_ntpServer">time.android.com</string>
     <!-- Normal polling frequency in milliseconds -->
     <integer name="config_ntpPollingInterval">86400000</integer>
     <!-- Try-again polling interval in milliseconds, in case the network request failed -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 200961f..deeaf35 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2752,6 +2752,11 @@
            <public name="exampleAttr1" />
            <public name="exampleAttr2" />
        </public-group>
+
+       To add a new public-group block, choose an id value that is 1 greater
+       than the last of that item above. For example, the last "attr" id
+       value above is 0x01010530, so the public-group of attrs below has
+       the id value of 0x01010531.
        =============================================================== -->
     <eat-comment />
 
@@ -2764,6 +2769,12 @@
         <public name="autoSizeStepGranularity" />
         <public name="autoSizeStepSizeSet" />
         <public name="autoSizeMinTextSize" />
+        <public name="min" />
+        <public name="rotationAnimation" />
+        <public name="layout_marginHorizontal" />
+        <public name="layout_marginVertical" />
+        <public name="paddingHorizontal" />
+        <public name="paddingVertical" />
     </public-group>
 
     <public-group type="style" first-id="0x010302e0">
@@ -2772,6 +2783,12 @@
     <public-group type="id" first-id="0x01020041">
     </public-group>
 
-    <public type="attr" name="min" />
-    <public type="attr" name="rotationAnimation" />
+  <!-- ===============================================================
+       DO NOT ADD UN-GROUPED ITEMS HERE
+
+       Any new items (attrs, styles, ids, etc.) *must* be added in a
+       public-group block, as the preceding comment explains.
+       Items added outside of a group may have their value recalculated
+       every time something new is added to this file.
+       =============================================================== -->
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 4070d48..423ec1f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1059,6 +1059,11 @@
       connected by a call.</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_readPhoneNumber">read phone number</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_readPhoneNumber">Allows the app to access the phone number of the device.</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_wakeLock" product="tablet">prevent tablet from sleeping</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_wakeLock" product="tv">prevent TV from sleeping</string>
@@ -4161,6 +4166,8 @@
         [CHAR LIMIT=20]
      -->
     <string name="managed_profile_label_badge">Work <xliff:g id="label" example="Email">%1$s</xliff:g></string>
+    <string name="managed_profile_label_badge_2">2nd Work <xliff:g id="label" example="Email">%1$s</xliff:g></string>
+    <string name="managed_profile_label_badge_3">3rd Work <xliff:g id="label" example="Email">%1$s</xliff:g></string>
 
     <!-- DO NOT TRANSLATE -->
     <string name="time_placeholder">--</string>
@@ -4446,6 +4453,6 @@
     <!-- Label used by Telephony code, assigned as the display name for conference calls [CHAR LIMIT=60] -->
     <string name="conference_call">Conference Call</string>
 
-    <!-- Title for a tooltip popup window [CHAR LIMIT=NONE] -->
-    <string name="tooltip_popup_title">Tooltip Popup</string>
+    <!-- Window title for a tooltip [CHAR LIMIT=NONE] -->
+    <string name="tooltip_popup_title">Tooltip</string>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a28a6fd..a17d2f1 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1017,6 +1017,8 @@
   <java-symbol type="string" name="action_bar_home_subtitle_description_format" />
   <java-symbol type="string" name="wireless_display_route_description" />
   <java-symbol type="string" name="managed_profile_label_badge" />
+  <java-symbol type="string" name="managed_profile_label_badge_2" />
+  <java-symbol type="string" name="managed_profile_label_badge_3" />
   <java-symbol type="string" name="mediasize_unknown_portrait" />
   <java-symbol type="string" name="mediasize_unknown_landscape" />
   <java-symbol type="string" name="mediasize_iso_a0" />
@@ -1269,12 +1271,15 @@
   <java-symbol type="drawable" name="cling_button" />
   <java-symbol type="drawable" name="cling_arrow_up" />
   <java-symbol type="drawable" name="cling_bg" />
-  <java-symbol type="drawable" name="ic_corp_badge" />
+  <java-symbol type="drawable" name="ic_corp_badge_color" />
+  <java-symbol type="drawable" name="ic_corp_badge_case" />
+  <java-symbol type="drawable" name="ic_corp_icon" />
   <java-symbol type="drawable" name="ic_corp_badge_off" />
-  <java-symbol type="drawable" name="ic_corp_icon_badge" />
+  <java-symbol type="drawable" name="ic_corp_icon_badge_shadow" />
+  <java-symbol type="drawable" name="ic_corp_icon_badge_color" />
+  <java-symbol type="drawable" name="ic_corp_icon_badge_case" />
   <java-symbol type="drawable" name="ic_corp_user_badge" />
   <java-symbol type="drawable" name="ic_corp_badge_no_background" />
-  <java-symbol type="drawable" name="ic_corp_icon" />
   <java-symbol type="drawable" name="ic_corp_statusbar_icon" />
   <java-symbol type="drawable" name="emulator_circular_window_overlay" />
 
@@ -1301,6 +1306,9 @@
   <java-symbol type="color" name="user_icon_8" />
   <java-symbol type="color" name="user_icon_default_gray" />
   <java-symbol type="color" name="user_icon_default_white" />
+  <java-symbol type="color" name="profile_badge_1" />
+  <java-symbol type="color" name="profile_badge_2" />
+  <java-symbol type="color" name="profile_badge_3" />
 
   <java-symbol type="layout" name="action_bar_home" />
   <java-symbol type="layout" name="action_bar_title_item" />
@@ -1708,6 +1716,7 @@
   <java-symbol type="bool" name="config_wifi_background_scan_support" />
   <java-symbol type="bool" name="config_wifi_dual_band_support" />
   <java-symbol type="bool" name="config_wifi_hotspot2_enabled" />
+  <java-symbol type="bool" name="config_wifi_fast_bss_transition_enabled" />
   <java-symbol type="bool" name="config_wimaxEnabled" />
   <java-symbol type="bool" name="show_ongoing_ime_switcher" />
   <java-symbol type="color" name="config_defaultNotificationColor" />
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index a15cba0..33a0493 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -620,7 +620,7 @@
                 try {
                     pkgInfo = pm.getPackageInfo(pkg,
                             PackageManager.GET_PERMISSIONS
-                            | PackageManager.GET_UNINSTALLED_PACKAGES);
+                            | PackageManager.MATCH_UNINSTALLED_PACKAGES);
                 } catch (NameNotFoundException e) {
                     pkgInfo = null;
                 }
@@ -712,7 +712,7 @@
             // Make sure the package doesn't exist
             try {
                 ApplicationInfo appInfo = pm.getApplicationInfo(pkg.packageName,
-                        PackageManager.GET_UNINSTALLED_PACKAGES);
+                        PackageManager.MATCH_UNINSTALLED_PACKAGES);
                 GenericReceiver receiver = new DeleteReceiver(pkg.packageName);
                 invokeDeletePackage(pkg.packageName, 0, receiver);
             } catch (NameNotFoundException e) {
@@ -974,7 +974,7 @@
     public boolean invokeDeletePackage(final String pkgName, int flags, GenericReceiver receiver)
             throws Exception {
         ApplicationInfo info = getPm().getApplicationInfo(pkgName,
-                PackageManager.GET_UNINSTALLED_PACKAGES);
+                PackageManager.MATCH_UNINSTALLED_PACKAGES);
 
         mContext.registerReceiver(receiver, receiver.filter);
         try {
@@ -1019,7 +1019,7 @@
             Log.i(TAG, "okay4");
             try {
                 info = getPm().getApplicationInfo(ip.pkg.packageName,
-                        PackageManager.GET_UNINSTALLED_PACKAGES);
+                        PackageManager.MATCH_UNINSTALLED_PACKAGES);
             } catch (NameNotFoundException e) {
                 info = null;
             }
@@ -1323,7 +1323,7 @@
 
         ApplicationInfo info = null;
         try {
-            info = getPm().getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
+            info = getPm().getApplicationInfo(packageName, PackageManager.MATCH_UNINSTALLED_PACKAGES);
         } catch (NameNotFoundException ignored) {
         }
 
@@ -1350,7 +1350,7 @@
         Log.i(TAG, "Deleting package : " + pkgName);
         try {
             ApplicationInfo info = getPm().getApplicationInfo(pkgName,
-                    PackageManager.GET_UNINSTALLED_PACKAGES);
+                    PackageManager.MATCH_UNINSTALLED_PACKAGES);
 
             if (info != null) {
                 DeleteObserver observer = new DeleteObserver(pkgName);
@@ -3756,7 +3756,7 @@
 
     public void testGetUnInstalledPackages() throws Exception {
         List<PackageInfo> packages = getPm().getInstalledPackages(
-                PackageManager.GET_UNINSTALLED_PACKAGES);
+                PackageManager.MATCH_UNINSTALLED_PACKAGES);
         assertNotNull("installed packages cannot be null", packages);
         assertTrue("installed packages cannot be empty", packages.size() > 0);
     }
@@ -3769,7 +3769,7 @@
                 | PackageManager.GET_CONFIGURATIONS | PackageManager.GET_INSTRUMENTATION
                 | PackageManager.GET_PERMISSIONS | PackageManager.GET_PROVIDERS
                 | PackageManager.GET_RECEIVERS | PackageManager.GET_SERVICES
-                | PackageManager.GET_SIGNATURES | PackageManager.GET_UNINSTALLED_PACKAGES;
+                | PackageManager.GET_SIGNATURES | PackageManager.MATCH_UNINSTALLED_PACKAGES;
 
         final InstallParams ip =
                 installFromRawResource("install.apk", R.raw.install_complete_package_info,
@@ -3809,12 +3809,12 @@
      * flags when the GET_UNINSTALLED_PACKAGES flag is set.
      */
     public void testGetUnInstalledPackagesAll() throws Exception {
-        final int flags = PackageManager.GET_UNINSTALLED_PACKAGES
+        final int flags = PackageManager.MATCH_UNINSTALLED_PACKAGES
                 | PackageManager.GET_ACTIVITIES | PackageManager.GET_GIDS
                 | PackageManager.GET_CONFIGURATIONS | PackageManager.GET_INSTRUMENTATION
                 | PackageManager.GET_PERMISSIONS | PackageManager.GET_PROVIDERS
                 | PackageManager.GET_RECEIVERS | PackageManager.GET_SERVICES
-                | PackageManager.GET_SIGNATURES | PackageManager.GET_UNINSTALLED_PACKAGES;
+                | PackageManager.GET_SIGNATURES;
 
         // first, install the package
         final InstallParams ip =
diff --git a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
index e7aca78..02c2517 100644
--- a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
+++ b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
@@ -42,6 +42,8 @@
     @Mock private Context mMockContext;
     @Mock private PackageManager mMockPm;
 
+    private NetworkScorerAppManager mNetworkScorerAppManager;
+
     @Override
     public void setUp() throws Exception {
         super.setUp();
@@ -54,6 +56,7 @@
 
         MockitoAnnotations.initMocks(this);
         Mockito.when(mMockContext.getPackageManager()).thenReturn(mMockPm);
+        mNetworkScorerAppManager = new NetworkScorerAppManager(mMockContext);
     }
 
     public void testGetAllValidScorers() throws Exception {
@@ -81,7 +84,7 @@
         setScorers(scorers);
 
         Iterator<NetworkScorerAppData> result =
-                NetworkScorerAppManager.getAllValidScorers(mMockContext).iterator();
+                mNetworkScorerAppManager.getAllValidScorers().iterator();
 
         assertTrue(result.hasNext());
         NetworkScorerAppData next = result.next();
diff --git a/docs/html/reference/images/graphics/colorspace_clipped.png b/docs/html/reference/images/graphics/colorspace_clipped.png
new file mode 100644
index 0000000..28204e6
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_clipped.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_comparison.png b/docs/html/reference/images/graphics/colorspace_comparison.png
new file mode 100644
index 0000000..b1b015c
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_comparison.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_comparison2.png b/docs/html/reference/images/graphics/colorspace_comparison2.png
new file mode 100644
index 0000000..b263aa1f
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_comparison2.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_points.png b/docs/html/reference/images/graphics/colorspace_points.png
new file mode 100644
index 0000000..84d1e77
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_points.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_renderer.png b/docs/html/reference/images/graphics/colorspace_renderer.png
new file mode 100644
index 0000000..acf30c3
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_renderer.png
Binary files differ
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 4f2465f..7dc5de3 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -16,12 +16,16 @@
 
 package android.graphics;
 
+import android.annotation.ColorInt;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Size;
 import android.annotation.Nullable;
+import android.util.Pair;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import java.util.function.DoubleUnaryOperator;
 
 /**
@@ -118,11 +122,38 @@
  * and {@link #connect(ColorSpace, ColorSpace)}, are also guaranteed to be
  * thread-safe.</p>
  *
+ * <h3>Visualization and debugging</h3>
+ *
+ * <p>To visualize and debug color spaces, you can call {@link #createRenderer()}.
+ * The {@link Renderer} created by calling this method can be used to compare
+ * color spaces and locate specific colors on a CIE 1931 chromaticity diagram.</p>
+ *
+ * <p>The following code snippet shows how to render a bitmap that compares
+ * the color gamuts and white points of {@link Named#DCI_P3} and
+ * {@link Named#PRO_PHOTO_RGB}:</p>
+ *
+ * <pre class="prettyprint">
+ * Bitmap bitmap = ColorSpace.createRenderer()
+ *     .size(768)
+ *     .clip(true)
+ *     .add(ColorSpace.get(ColorSpace.Named.DCI_P3), 0xffffc845)
+ *     .add(ColorSpace.get(ColorSpace.Named.PRO_PHOTO_RGB), 0xff097ae9)
+ *     .render();
+ * </pre>
+ * <p>
+ *     <img src="{@docRoot}reference/android/images/graphics/colorspace_renderer.png" />
+ *     <figcaption style="text-align: center;">DCI-P3 vs ProPhoto RGB</figcaption>
+ * </p>
+ *
+ * <p>Please refer to the documentation of the {@link Renderer} class for more
+ * information about its options and capabilities.</p>
+ *
  * @see #get(Named)
  * @see Named
  * @see Model
  * @see Connector
  * @see Adaptation
+ * @see Renderer
  */
 @SuppressWarnings("StaticInitializerReferencesSubClass")
 public abstract class ColorSpace {
@@ -1333,6 +1364,20 @@
         return sNamedColorSpaces[name.ordinal()];
     }
 
+    /**
+     * <p>Creates a new {@link Renderer} that can be used to visualize and
+     * debug color spaces. See the documentation of {@link Renderer} for
+     * more information.</p>
+     *
+     * @return A new non-null {@link Renderer} instance
+     *
+     * @see Renderer
+     */
+    @NonNull
+    public static Renderer createRenderer() {
+        return new Renderer();
+    }
+
     static {
         sNamedColorSpaces[Named.SRGB.ordinal()] = new ColorSpace.Rgb(
                 "sRGB IEC61966-2.1",
@@ -3113,4 +3158,688 @@
             };
         }
     }
+
+    /**
+     * <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>
+     *
+     * <p>The following code snippet shows how to compare the {@link Named#SRGB}
+     * and {@link Named#DCI_P3} color spaces:</p>
+     *
+     * <pre class="prettyprint">
+     * Bitmap bitmap = ColorSpace.createRenderer()
+     *     .size(768)
+     *     .clip(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_clipped.png" />
+     *     <figcaption style="text-align: center;">sRGB vs DCI-P3</figcaption>
+     * </p>
+     *
+     * <p>A renderer can also be used to show the location of specific colors,
+     * associated with a color space, in the CIE 1931 xyY chromaticity diagram.
+     * See {@link #add(ColorSpace, float, float, float, int)} for more information.</p>
+     *
+     * @see ColorSpace#createRenderer()
+     */
+    public static class Renderer {
+        private static final int NATIVE_SIZE = 1440;
+
+        @IntRange(from = 128, to = Integer.MAX_VALUE)
+        private int mSize = 1024;
+
+        private boolean mShowWhitePoint = true;
+        private boolean mClip = false;
+
+        private final List<Pair<ColorSpace, Integer>> mColorSpaces = new ArrayList<>(2);
+        private final List<Point> mPoints = new ArrayList<>(0);
+
+        private Renderer() {
+        }
+
+        /**
+         * <p>Defines whether the chromaticity diagram should be clipped by the first
+         * registered color space. The default value is false.</p>
+         *
+         * <p>The following code snippet and image show the default behavior:</p>
+         * <pre class="prettyprint">
+         * Bitmap bitmap = ColorSpace.createRenderer()
+         *     .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_comparison.png" />
+         *     <figcaption style="text-align: center;">Clipping disabled</figcaption>
+         * </p>
+         *
+         * <p>Here is the same example with clipping enabled:</p>
+         * <pre class="prettyprint">
+         * Bitmap bitmap = ColorSpace.createRenderer()
+         *     .clip(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_clipped.png" />
+         *     <figcaption style="text-align: center;">Clipping enabled</figcaption>
+         * </p>
+         *
+         * @param clip True to clip the chromaticity diagram to the first registered color space,
+         *             false otherwise
+         * @return This instance of {@link Renderer}
+         */
+        @NonNull
+        public Renderer clip(boolean clip) {
+            mClip = clip;
+            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.
+         *
+         * @param size The size in pixels of the output bitmap
+         * @return This instance of {@link Renderer}
+         */
+        @NonNull
+        public Renderer size(@IntRange(from = 128, to = Integer.MAX_VALUE) int size) {
+            mSize = Math.max(128, size);
+            return this;
+        }
+
+        /**
+         * Shows or hides the white point of each color space in the output bitmap.
+         * The default is true.
+         *
+         * @param show True to show the white point of each color space, false
+         *             otherwise
+         * @return This instance of {@link Renderer}
+         */
+        @NonNull
+        public Renderer showWhitePoint(boolean show) {
+            mShowWhitePoint = show;
+            return this;
+        }
+
+        /**
+         * <p>Adds a color space to represent on the output CIE 1931 chromaticity
+         * diagram. The color space is represented as a triangle showing the
+         * footprint of its color gamut and, optionally, the location of its
+         * white point.</p>
+         *
+         * <p class="note">Color spaces with a color model that is not RGB are
+         * accepted but ignored.</p>
+         *
+         * <p>The following code snippet and image show an example of calling this
+         * method to compare {@link Named#SRGB sRGB} and {@link Named#DCI_P3 DCI-P3}:</p>
+         * <pre class="prettyprint">
+         * Bitmap bitmap = ColorSpace.createRenderer()
+         *     .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_comparison.png" />
+         *     <figcaption style="text-align: center;">sRGB vs DCI-P3</figcaption>
+         * </p>
+         *
+         * <p>Adding a color space extending beyond the boundaries of the
+         * spectral locus will alter the size of the diagram within the output
+         * bitmap as shown in this example:</p>
+         * <pre class="prettyprint">
+         * Bitmap bitmap = ColorSpace.createRenderer()
+         *     .add(ColorSpace.get(ColorSpace.Named.SRGB), 0xffffffff)
+         *     .add(ColorSpace.get(ColorSpace.Named.DCI_P3), 0xffffc845)
+         *     .add(ColorSpace.get(ColorSpace.Named.ACES), 0xff097ae9)
+         *     .add(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB), 0xff000000)
+         *     .render();
+         * </pre>
+         * <p>
+         *     <img src="{@docRoot}reference/android/images/graphics/colorspace_comparison2.png" />
+         *     <figcaption style="text-align: center;">sRGB vs DCI-P3</figcaption>
+         * </p>
+         *
+         * @param colorSpace The color space whose gamut to render on the diagram
+         * @param color The sRGB color to use to render the color space's gamut and white point
+         * @return This instance of {@link Renderer}
+         *
+         * @see #clip(boolean)
+         * @see #showWhitePoint(boolean)
+         */
+        @NonNull
+        public Renderer add(@NonNull ColorSpace colorSpace, @ColorInt int color) {
+            mColorSpaces.add(new Pair<>(colorSpace, color));
+            return this;
+        }
+
+        /**
+         * <p>Adds a color to represent as a point on the chromaticity diagram.
+         * The color is associated with a color space which will be used to
+         * perform the conversion to CIE XYZ and compute the location of the point
+         * on the diagram. The point is rendered as a colored circle.</p>
+         *
+         * <p>The following code snippet and image show an example of calling this
+         * method to render the location of several sRGB colors as white circles:</p>
+         * <pre class="prettyprint">
+         * Bitmap bitmap = ColorSpace.createRenderer()
+         *     .clip(true)
+         *     .add(ColorSpace.get(ColorSpace.Named.SRGB), 0xffffffff)
+         *     .add(ColorSpace.get(ColorSpace.Named.SRGB), 0.1f, 0.0f, 0.1f, 0xffffffff)
+         *     .add(ColorSpace.get(ColorSpace.Named.SRGB), 0.1f, 0.1f, 0.1f, 0xffffffff)
+         *     .add(ColorSpace.get(ColorSpace.Named.SRGB), 0.1f, 0.2f, 0.1f, 0xffffffff)
+         *     .add(ColorSpace.get(ColorSpace.Named.SRGB), 0.1f, 0.3f, 0.1f, 0xffffffff)
+         *     .add(ColorSpace.get(ColorSpace.Named.SRGB), 0.1f, 0.4f, 0.1f, 0xffffffff)
+         *     .add(ColorSpace.get(ColorSpace.Named.SRGB), 0.1f, 0.5f, 0.1f, 0xffffffff)
+         *     .render();
+         * </pre>
+         * <p>
+         *     <img src="{@docRoot}reference/android/images/graphics/colorspace_points.png" />
+         *     <figcaption style="text-align: center;">
+         *         Locating colors on the chromaticity diagram
+         *     </figcaption>
+         * </p>
+         *
+         * @param colorSpace The color space of the color to locate on the diagram
+         * @param r The first component of the color to locate on the diagram
+         * @param g The second component of the color to locate on the diagram
+         * @param b The third component of the color to locate on the diagram
+         * @param pointColor The sRGB color to use to render the point on the diagram
+         * @return This instance of {@link Renderer}
+         */
+        @NonNull
+        public Renderer add(@NonNull ColorSpace colorSpace, float r, float g, float b,
+                @ColorInt int pointColor) {
+            mPoints.add(new Point(colorSpace, new float[] { r, g, b }, pointColor));
+            return this;
+        }
+
+        /**
+         * <p>Renders the {@link #add(ColorSpace, int) color spaces} and
+         * {@link #add(ColorSpace, float, float, float, int) points} registered
+         * with this renderer. The output bitmap is an sRGB image with the
+         * dimensions specified by calling {@link #size(int)} (1204x1024px by
+         * default).</p>
+         *
+         * @return A new non-null {@link Bitmap} with the dimensions specified
+         *        by {@link #size(int)} (1024x1024 by default)
+         */
+        @NonNull
+        public Bitmap render() {
+            Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+            Bitmap bitmap = Bitmap.createBitmap(mSize, mSize, Bitmap.Config.ARGB_8888);
+            Canvas canvas = new Canvas(bitmap);
+
+            float[] primaries = new float[6];
+            float[] whitePoint = new float[2];
+
+            int width = NATIVE_SIZE;
+            int height = NATIVE_SIZE;
+
+            Path path = new Path();
+
+            setTransform(canvas, width, height, primaries);
+            drawBox(canvas, width, height, paint, path);
+            drawLocus(canvas, width, height, paint, path, primaries);
+            drawGamuts(canvas, width, height, paint, path, primaries, whitePoint);
+            drawPoints(canvas, width, height, paint);
+
+            return bitmap;
+        }
+
+        /**
+         * Draws registered points at their correct position in the xyY coordinates.
+         * Each point is positioned according to its associated color space.
+         *
+         * @param canvas The canvas to transform
+         * @param width Width in pixel of the final image
+         * @param height Height in pixel of the final image
+         * @param paint A pre-allocated paint used to avoid temporary allocations
+         */
+        private void drawPoints(@NonNull Canvas canvas, int width, int height,
+                @NonNull Paint paint) {
+
+            paint.setStyle(Paint.Style.FILL);
+
+            float[] v = new float[3];
+            for (final Point point : mPoints) {
+                v[0] = point.mRgb[0];
+                v[1] = point.mRgb[1];
+                v[2] = point.mRgb[2];
+                point.mColorSpace.toXyz(v);
+
+                paint.setColor(point.mColor);
+
+                // XYZ to xyY, assuming Y=1.0
+                float sum = v[0] + v[1] + v[2];
+                canvas.drawCircle(width * v[0] / sum, height - height * v[1] / sum,
+                        4.0f, paint);
+            }
+        }
+
+        /**
+         * Draws the color gamuts and white points of all the registered color
+         * spaces. Only color spaces with an RGB color model are rendered, the
+         * others are ignored.
+         *
+         * @param canvas The canvas to transform
+         * @param width Width in pixel of the final image
+         * @param height Height in pixel of the final image
+         * @param paint A pre-allocated paint used to avoid temporary allocations
+         * @param path A pre-allocated path used to avoid temporary allocations
+         * @param primaries A pre-allocated array of 6 floats to avoid temporary allocations
+         * @param whitePoint A pre-allocated array of 2 floats to avoid temporary allocations
+         */
+        private void drawGamuts(
+                @NonNull Canvas canvas, int width, int height,
+                @NonNull Paint paint, @NonNull Path path,
+                @NonNull @Size(6) float[] primaries, @NonNull @Size(2) float[] whitePoint) {
+
+            for (final Pair<ColorSpace, Integer> item : mColorSpaces) {
+                ColorSpace colorSpace = item.first;
+                int color = item.second;
+
+                if (colorSpace.getModel() != Model.RGB) continue;
+
+                Rgb rgb = (Rgb) colorSpace;
+                getPrimaries(rgb, primaries);
+
+                path.rewind();
+                path.moveTo(width * primaries[0], height - height * primaries[1]);
+                path.lineTo(width * primaries[2], height - height * primaries[3]);
+                path.lineTo(width * primaries[4], height - height * primaries[5]);
+                path.close();
+
+                paint.setStyle(Paint.Style.STROKE);
+                paint.setColor(color);
+                canvas.drawPath(path, paint);
+
+                // Draw the white point
+                if (mShowWhitePoint) {
+                    rgb.getWhitePoint(whitePoint);
+
+                    paint.setStyle(Paint.Style.FILL);
+                    paint.setColor(color);
+                    canvas.drawCircle(width * whitePoint[0], height - height * whitePoint[1],
+                            4.0f, paint);
+                }
+            }
+        }
+
+        /**
+         * Returns the primaries of the specified RGB color space. This method handles
+         * the special case of the {@link Named#EXTENDED_SRGB} family of color spaces.
+         *
+         * @param rgb The color space whose primaries to extract
+         * @param primaries A pre-allocated array of 6 floats that will hold the result
+         */
+        @NonNull
+        @Size(6)
+        private static float[] getPrimaries(@NonNull Rgb rgb, @NonNull @Size(6) float[] primaries) {
+            // 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))) {
+                primaries[0] = 1.41f;
+                primaries[1] = 0.33f;
+                primaries[2] = 0.27f;
+                primaries[3] = 1.24f;
+                primaries[4] = -0.23f;
+                primaries[5] = -0.57f;
+                return primaries;
+            }
+            return rgb.getPrimaries(primaries);
+        }
+
+        /**
+         * Draws the CIE 1931 chromaticity diagram: the spectral locus and its inside.
+         * This method respect the clip parameter.
+         *
+         * @param canvas The canvas to transform
+         * @param width Width in pixel of the final image
+         * @param height Height in pixel of the final image
+         * @param paint A pre-allocated paint used to avoid temporary allocations
+         * @param path A pre-allocated path used to avoid temporary allocations
+         * @param primaries A pre-allocated array of 6 floats to avoid temporary allocations
+         */
+        private void drawLocus(
+                @NonNull Canvas canvas, int width, int height, @NonNull Paint paint,
+                @NonNull Path path, @NonNull @Size(6) float[] primaries) {
+
+            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);
+
+            // Draw the spectral locus
+            if (mClip && mColorSpaces.size() > 0) {
+                for (final Pair<ColorSpace, Integer> item : mColorSpaces) {
+                    ColorSpace colorSpace = item.first;
+                    if (colorSpace.getModel() != Model.RGB) continue;
+
+                    Rgb rgb = (Rgb) colorSpace;
+                    getPrimaries(rgb, primaries);
+                    break;
+                }
+
+                path.rewind();
+                path.moveTo(width * primaries[0], height - height * primaries[1]);
+                path.lineTo(width * primaries[2], height - height * primaries[3]);
+                path.lineTo(width * primaries[4], height - height * primaries[5]);
+                path.close();
+
+                int[] solid = new int[colors.length];
+                Arrays.fill(solid, 0xff6c6c6c);
+                canvas.drawVertices(Canvas.VertexMode.TRIANGLES, vertices.length, vertices, 0,
+                        null, 0, solid, 0, null, 0, 0, paint);
+
+                canvas.save();
+                canvas.clipPath(path);
+
+                canvas.drawVertices(Canvas.VertexMode.TRIANGLES, vertices.length, vertices, 0,
+                        null, 0, colors, 0, null, 0, 0, paint);
+
+                canvas.restore();
+            } else {
+                canvas.drawVertices(Canvas.VertexMode.TRIANGLES, vertices.length, vertices, 0,
+                        null, 0, colors, 0, null, 0, 0, paint);
+            }
+
+            // Draw the non-spectral locus
+            int index = (CHROMATICITY_RESOLUTION - 1) * 12;
+            path.reset();
+            path.moveTo(vertices[index], vertices[index + 1]);
+            for (int x = 2; x < SPECTRUM_LOCUS_X.length; x++) {
+                index += CHROMATICITY_RESOLUTION * 12;
+                path.lineTo(vertices[index], vertices[index + 1]);
+            }
+            path.close();
+
+            paint.setStyle(Paint.Style.STROKE);
+            paint.setColor(0xff000000);
+            canvas.drawPath(path, paint);
+        }
+
+        /**
+         * Draws the diagram box, including borders, tick marks, grid lines
+         * and axis labels.
+         *
+         * @param canvas The canvas to transform
+         * @param width Width in pixel of the final image
+         * @param height Height in pixel of the final image
+         * @param paint A pre-allocated paint used to avoid temporary allocations
+         * @param path A pre-allocated path used to avoid temporary allocations
+         */
+        private void drawBox(@NonNull Canvas canvas, int width, int height, @NonNull Paint paint,
+                @NonNull Path path) {
+            // 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);
+            }
+
+            // 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);
+            }
+
+            // Draw the axis labels
+            paint.setStyle(Paint.Style.FILL);
+            paint.setTextSize(36.0f);
+            paint.setTypeface(Typeface.create("sans-serif-light", Typeface.NORMAL));
+
+            Rect bounds = new Rect();
+            for (int i = 1; i < 9; 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 x = width * i / 10.0f;
+                canvas.drawText(text, x - bounds.width() / 2.0f,
+                        height + bounds.height() + 16, paint);
+            }
+            paint.setStyle(Paint.Style.STROKE);
+
+            // Draw the diagram box
+            path.moveTo(0.0f, height);
+            path.lineTo(0.9f * width, height);
+            path.lineTo(0.9f * width, 0.1f * height);
+            path.lineTo(0.0f, 0.1f * height);
+            path.close();
+            canvas.drawPath(path, paint);
+        }
+
+        /**
+         * Computes and applies the Canvas transforms required to make the color
+         * gamut of each color space visible in the final image.
+         *
+         * @param canvas The canvas to transform
+         * @param width Width in pixel of the final image
+         * @param height Height in pixel of the final image
+         * @param primaries Array of 6 floats used to avoid temporary allocations
+         */
+        private void setTransform(@NonNull Canvas canvas, int width, int height,
+                @NonNull @Size(6) float[] primaries) {
+
+            RectF primariesBounds = new RectF();
+            for (final Pair<ColorSpace, Integer> item : mColorSpaces) {
+                ColorSpace colorSpace = item.first;
+                if (colorSpace.getModel() != Model.RGB) continue;
+
+                Rgb rgb = (Rgb) colorSpace;
+                getPrimaries(rgb, primaries);
+
+                primariesBounds.left = Math.min(primariesBounds.left, primaries[4]);
+                primariesBounds.top = Math.min(primariesBounds.top, primaries[5]);
+                primariesBounds.right = Math.max(primariesBounds.right, primaries[0]);
+                primariesBounds.bottom = Math.max(primariesBounds.bottom, primaries[3]);
+            }
+
+            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);
+
+            float scaleX = 0.9f / primariesBounds.width();
+            float scaleY = 0.9f / 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);
+
+            // 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);
+        }
+
+        // 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,
+                0.146958f, 0.139149f, 0.133536f, 0.126688f, 0.115830f,
+                0.109616f, 0.099146f, 0.091310f, 0.078130f, 0.068717f,
+                0.054675f, 0.040763f, 0.027497f, 0.016270f, 0.008169f,
+                0.004876f, 0.003983f, 0.003859f, 0.004646f, 0.007988f,
+                0.013870f, 0.022244f, 0.027273f, 0.032820f, 0.038851f,
+                0.045327f, 0.052175f, 0.059323f, 0.066713f, 0.074299f,
+                0.089937f, 0.114155f, 0.138695f, 0.154714f, 0.192865f,
+                0.229607f, 0.265760f, 0.301588f, 0.337346f, 0.373083f,
+                0.408717f, 0.444043f, 0.478755f, 0.512467f, 0.544767f,
+                0.575132f, 0.602914f, 0.627018f, 0.648215f, 0.665746f,
+                0.680061f, 0.691487f, 0.700589f, 0.707901f, 0.714015f,
+                0.719017f, 0.723016f, 0.734674f, 0.717203f, 0.699732f,
+                0.682260f, 0.664789f, 0.647318f, 0.629847f, 0.612376f,
+                0.594905f, 0.577433f, 0.559962f, 0.542491f, 0.525020f,
+                0.507549f, 0.490077f, 0.472606f, 0.455135f, 0.437664f,
+                0.420193f, 0.402721f, 0.385250f, 0.367779f, 0.350308f,
+                0.332837f, 0.315366f, 0.297894f, 0.280423f, 0.262952f,
+                0.245481f, 0.228010f, 0.210538f, 0.193067f, 0.175596f
+        };
+        // Y coordinates of the spectral locus in CIE 1931
+        private static final float[] SPECTRUM_LOCUS_Y = {
+                0.005295f, 0.004800f, 0.005472f, 0.005976f, 0.014496f,
+                0.026643f, 0.035211f, 0.042704f, 0.053441f, 0.073601f,
+                0.086866f, 0.112037f, 0.132737f, 0.170464f, 0.200773f,
+                0.254155f, 0.317049f, 0.387997f, 0.463035f, 0.538504f,
+                0.587196f, 0.610526f, 0.654897f, 0.675970f, 0.715407f,
+                0.750246f, 0.779682f, 0.792153f, 0.802971f, 0.812059f,
+                0.819430f, 0.825200f, 0.829460f, 0.832306f, 0.833833f,
+                0.833316f, 0.826231f, 0.814796f, 0.805884f, 0.781648f,
+                0.754347f, 0.724342f, 0.692326f, 0.658867f, 0.624470f,
+                0.589626f, 0.554734f, 0.520222f, 0.486611f, 0.454454f,
+                0.424252f, 0.396516f, 0.372510f, 0.351413f, 0.334028f,
+                0.319765f, 0.308359f, 0.299317f, 0.292044f, 0.285945f,
+                0.280951f, 0.276964f, 0.265326f, 0.257200f, 0.249074f,
+                0.240948f, 0.232822f, 0.224696f, 0.216570f, 0.208444f,
+                0.200318f, 0.192192f, 0.184066f, 0.175940f, 0.167814f,
+                0.159688f, 0.151562f, 0.143436f, 0.135311f, 0.127185f,
+                0.119059f, 0.110933f, 0.102807f, 0.094681f, 0.086555f,
+                0.078429f, 0.070303f, 0.062177f, 0.054051f, 0.045925f,
+                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) {
+
+            ColorSpace colorSpace = get(Named.SRGB);
+
+            float[] color = new float[3];
+
+            int vertexIndex = 0;
+            int colorIndex = 0;
+
+            for (int x = 0; x < SPECTRUM_LOCUS_X.length; x++) {
+                int nextX = (x % (SPECTRUM_LOCUS_X.length - 1)) + 1;
+
+                float a1 = (float) Math.atan2(
+                        SPECTRUM_LOCUS_Y[x] - ONE_THIRD,
+                        SPECTRUM_LOCUS_X[x] - ONE_THIRD);
+                float a2 = (float) Math.atan2(
+                        SPECTRUM_LOCUS_Y[nextX] - ONE_THIRD,
+                        SPECTRUM_LOCUS_X[nextX] - ONE_THIRD);
+
+                float radius1 = (float) Math.pow(
+                        sqr(SPECTRUM_LOCUS_X[x] - ONE_THIRD) +
+                                sqr(SPECTRUM_LOCUS_Y[x] - ONE_THIRD),
+                        0.5);
+                float radius2 = (float) Math.pow(
+                        sqr(SPECTRUM_LOCUS_X[nextX] - ONE_THIRD) +
+                                sqr(SPECTRUM_LOCUS_Y[nextX] - ONE_THIRD),
+                        0.5);
+
+                // Compute patches; each patch is a quad with a different
+                // color associated with each vertex
+                for (int c = 1; c <= CHROMATICITY_RESOLUTION; c++) {
+                    float f1 = c / (float) CHROMATICITY_RESOLUTION;
+                    float f2 = (c - 1) / (float) CHROMATICITY_RESOLUTION;
+
+                    double cr1 = radius1 * Math.cos(a1);
+                    double sr1 = radius1 * Math.sin(a1);
+                    double cr2 = radius2 * Math.cos(a2);
+                    double sr2 = radius2 * Math.sin(a2);
+
+                    // Compute the XYZ coordinates of the 4 vertices of the patch
+                    float v1x = (float) (ONE_THIRD + cr1 * f1);
+                    float v1y = (float) (ONE_THIRD + sr1 * f1);
+                    float v1z = 1 - v1x - v1y;
+
+                    float v2x = (float) (ONE_THIRD + cr1 * f2);
+                    float v2y = (float) (ONE_THIRD + sr1 * f2);
+                    float v2z = 1 - v2x - v2y;
+
+                    float v3x = (float) (ONE_THIRD + cr2 * f2);
+                    float v3y = (float) (ONE_THIRD + sr2 * f2);
+                    float v3z = 1 - v3x - v3y;
+
+                    float v4x = (float) (ONE_THIRD + cr2 * f1);
+                    float v4y = (float) (ONE_THIRD + sr2 * f1);
+                    float v4z = 1 - v4x - v4y;
+
+                    // Compute the sRGB representation of each XYZ coordinate of the patch
+                    colors[colorIndex    ] = computeColor(color, v1x, v1y, v1z, colorSpace);
+                    colors[colorIndex + 1] = computeColor(color, v2x, v2y, v2z, colorSpace);
+                    colors[colorIndex + 2] = computeColor(color, v3x, v3y, v3z, colorSpace);
+                    colors[colorIndex + 3] = colors[colorIndex];
+                    colors[colorIndex + 4] = colors[colorIndex + 2];
+                    colors[colorIndex + 5] = computeColor(color, v4x, v4y, v4z, colorSpace);
+                    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;
+                }
+            }
+        }
+
+        @ColorInt
+        private static int computeColor(@NonNull @Size(3) float[] color,
+                float x, float y, float z, @NonNull ColorSpace cs) {
+            color[0] = x;
+            color[1] = y;
+            color[2] = z;
+            cs.fromXyz(color);
+            return 0xff000000 |
+                    (((int) (color[0] * 255.0f) & 0xff) << 16) |
+                    (((int) (color[1] * 255.0f) & 0xff) <<  8) |
+                    (((int) (color[2] * 255.0f) & 0xff)      );
+        }
+
+        private static double sqr(double v) {
+            return v * v;
+        }
+
+        private static class Point {
+            @NonNull final ColorSpace mColorSpace;
+            @NonNull final float[] mRgb;
+            final int mColor;
+
+            Point(@NonNull ColorSpace colorSpace,
+                    @NonNull @Size(3) float[] rgb, @ColorInt int color) {
+                mColorSpace = colorSpace;
+                mRgb = rgb;
+                mColor = color;
+            }
+        }
+    }
 }
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index 7871aa8..9490436 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -21,6 +21,8 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
@@ -99,6 +101,67 @@
         }
     }
 
+    // Note that a well-formed variation contains a four-character tag and a float as styleValue,
+    // with spacers in between. The tag is enclosd either by double quotes or single quotes.
+    @VisibleForTesting
+    public static Axis[] parseFontVariationSettings(String settings) {
+        String[] settingList = settings.split(",");
+        ArrayList<Axis> axisList = new ArrayList<>();
+        settingLoop:
+        for (String setting : settingList) {
+            int pos = 0;
+            while (pos < setting.length()) {
+                char c = setting.charAt(pos);
+                if (c == '\'' || c == '"') {
+                    break;
+                } else if (!isSpacer(c)) {
+                    continue settingLoop;  // Only spacers are allowed before tag appeared.
+                }
+                pos++;
+            }
+            if (pos + 7 > setting.length()) {
+                continue;  // 7 is the minimum length of tag-style value pair text.
+            }
+            if (setting.charAt(pos) != setting.charAt(pos + 5)) {
+                continue;  // Tag should be wrapped with double or single quote.
+            }
+            String tagString = setting.substring(pos + 1, pos + 5);
+            if (!TAG_PATTERN.matcher(tagString).matches()) {
+                continue;  // Skip incorrect format tag.
+            }
+            pos += 6;
+            while (pos < setting.length()) {
+                if (!isSpacer(setting.charAt(pos++))) {
+                    break;  // Skip spacers between the tag and the styleValue.
+                }
+            }
+            // Skip invalid styleValue
+            float styleValue;
+            String valueString = setting.substring(pos - 1);
+            if (!STYLE_VALUE_PATTERN.matcher(valueString).matches()) {
+                continue;  // Skip incorrect format styleValue.
+            }
+            try {
+                styleValue = Float.parseFloat(valueString);
+            } catch (NumberFormatException e) {
+                continue;  // ignoreing invalid number format
+            }
+            int tag = makeTag(tagString.charAt(0), tagString.charAt(1), tagString.charAt(2),
+                    tagString.charAt(3));
+            axisList.add(new Axis(tag, styleValue));
+        }
+        return axisList.toArray(new Axis[axisList.size()]);
+    }
+
+    @VisibleForTesting
+    public static int makeTag(char c1, char c2, char c3, char c4) {
+        return (c1 << 24) | (c2 << 16) | (c3 << 8) | c4;
+    }
+
+    private static boolean isSpacer(char c) {
+        return c == ' ' || c == '\r' || c == '\t' || c == '\n';
+    }
+
     private static Config readFamilies(XmlPullParser parser)
             throws XmlPullParserException, IOException {
         Config config = new Config();
@@ -165,8 +228,10 @@
         return new Font(fullFilename, index, axes, weight, isItalic);
     }
 
-    /** The 'tag' attribute value is read as four character values between 0 and 255 inclusive. */
-    private static final Pattern TAG_PATTERN = Pattern.compile("[\\x00-\\xFF]{4}");
+    /** The 'tag' attribute value is read as four character values between U+0020 and U+007E
+     *  inclusive.
+     */
+    private static final Pattern TAG_PATTERN = Pattern.compile("[\\x20-\\x7E]{4}");
 
     /** The 'styleValue' attribute has an optional leading '-', followed by '<digits>',
      *  '<digits>.<digits>', or '.<digits>' where '<digits>' is one or more of [0-9].
@@ -179,10 +244,7 @@
         int tag = 0;
         String tagStr = parser.getAttributeValue(null, "tag");
         if (tagStr != null && TAG_PATTERN.matcher(tagStr).matches()) {
-            tag = (tagStr.charAt(0) << 24) +
-                  (tagStr.charAt(1) << 16) +
-                  (tagStr.charAt(2) <<  8) +
-                  (tagStr.charAt(3)      );
+            tag = makeTag(tagStr.charAt(0), tagStr.charAt(1), tagStr.charAt(2), tagStr.charAt(3));
         } else {
             throw new XmlPullParserException("Invalid tag attribute value.", parser, null);
         }
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index 2b950d3..9772009 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -299,7 +299,7 @@
                         final PackageManager pm = context.getPackageManager();
                         try {
                             ApplicationInfo ai = pm.getApplicationInfo(
-                                    resPackage, PackageManager.GET_UNINSTALLED_PACKAGES);
+                                    resPackage, PackageManager.MATCH_UNINSTALLED_PACKAGES);
                             if (ai != null) {
                                 mObj1 = pm.getResourcesForApplication(ai);
                             } else {
diff --git a/graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java b/graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java
new file mode 100644
index 0000000..d046c11
--- /dev/null
+++ b/graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+
+public class VariationParserTest extends TestCase {
+
+    @SmallTest
+    public void testParseFontVariationSetting() {
+        int tag = FontListParser.makeTag('w', 'd', 't', 'h');
+        FontListParser.Axis[] axis = FontListParser.parseFontVariationSettings("'wdth' 1");
+        assertEquals(tag, axis[0].tag);
+        assertEquals(1.0f, axis[0].styleValue);
+
+        axis = FontListParser.parseFontVariationSettings("\"wdth\" 100");
+        assertEquals(tag, axis[0].tag);
+        assertEquals(100.0f, axis[0].styleValue);
+
+        axis = FontListParser.parseFontVariationSettings("   'wdth' 100");
+        assertEquals(tag, axis[0].tag);
+        assertEquals(100.0f, axis[0].styleValue);
+
+        axis = FontListParser.parseFontVariationSettings("\t'wdth' 0.5");
+        assertEquals(tag, axis[0].tag);
+        assertEquals(0.5f, axis[0].styleValue);
+
+        tag = FontListParser.makeTag('A', 'X', ' ', ' ');
+        axis = FontListParser.parseFontVariationSettings("'AX  ' 1");
+        assertEquals(tag, axis[0].tag);
+        assertEquals(1.0f, axis[0].styleValue);
+
+        axis = FontListParser.parseFontVariationSettings("'AX  '\t1");
+        assertEquals(tag, axis[0].tag);
+        assertEquals(1.0f, axis[0].styleValue);
+
+        axis = FontListParser.parseFontVariationSettings("'AX  '\n1");
+        assertEquals(tag, axis[0].tag);
+        assertEquals(1.0f, axis[0].styleValue);
+
+        axis = FontListParser.parseFontVariationSettings("'AX  '\r1");
+        assertEquals(tag, axis[0].tag);
+        assertEquals(1.0f, axis[0].styleValue);
+
+        axis = FontListParser.parseFontVariationSettings("'AX  '\r\t\n 1");
+        assertEquals(tag, axis[0].tag);
+        assertEquals(1.0f, axis[0].styleValue);
+
+        // Test for invalid input
+        axis = FontListParser.parseFontVariationSettings("");
+        assertEquals(0, axis.length);
+        axis = FontListParser.parseFontVariationSettings("invalid_form");
+        assertEquals(0, axis.length);
+
+        // Test with invalid tag
+        axis = FontListParser.parseFontVariationSettings("'' 1");
+        assertEquals(0, axis.length);
+        axis = FontListParser.parseFontVariationSettings("'invalid' 1");
+        assertEquals(0, axis.length);
+
+        // Test with invalid styleValue
+        axis = FontListParser.parseFontVariationSettings("'wdth' ");
+        assertEquals(0, axis.length);
+        axis = FontListParser.parseFontVariationSettings("'wdth' x");
+        assertEquals(0, axis.length);
+        axis = FontListParser.parseFontVariationSettings("'wdth' \t");
+        assertEquals(0, axis.length);
+        axis = FontListParser.parseFontVariationSettings("'wdth' \n\r");
+        assertEquals(0, axis.length);
+    }
+
+    @SmallTest
+    public void testParseFontVariationStyleSettings() {
+        FontListParser.Axis[] axis =
+                FontListParser.parseFontVariationSettings("'wdth' 10,'AX  '\r1");
+        int tag1 = FontListParser.makeTag('w', 'd', 't', 'h');
+        int tag2 = FontListParser.makeTag('A', 'X', ' ', ' ');
+        assertEquals(tag1, axis[0].tag);
+        assertEquals(10.0f, axis[0].styleValue);
+        assertEquals(tag2, axis[1].tag);
+        assertEquals(1.0f, axis[1].styleValue);
+
+        // Test only spacers are allowed before tag
+        axis = FontListParser.parseFontVariationSettings("     'wdth' 10,ab'wdth' 1");
+        tag1 = FontListParser.makeTag('w', 'd', 't', 'h');
+        assertEquals(tag1, axis[0].tag);
+        assertEquals(10.0f, axis[0].styleValue);
+        assertEquals(1, axis.length);
+    }
+
+    @SmallTest
+    public void testInvalidTagCharacters() {
+        FontListParser.Axis[] axis =
+                FontListParser.parseFontVariationSettings("'\u0000\u0000\u0000\u0000' 10");
+        assertEquals(0, axis.length);
+        axis = FontListParser.parseFontVariationSettings("'\u3042\u3044\u3046\u3048' 10");
+        assertEquals(0, axis.length);
+    }
+
+    @SmallTest
+    public void testMakeTag() {
+      assertEquals(0x77647468, FontListParser.makeTag('w', 'd', 't', 'h'));
+      assertEquals(0x41582020, FontListParser.makeTag('A', 'X', ' ', ' '));
+      assertEquals(0x20202020, FontListParser.makeTag(' ', ' ', ' ', ' '));
+    }
+}
diff --git a/legacy-test/Android.mk b/legacy-test/Android.mk
new file mode 100644
index 0000000..fe5d8ca
--- /dev/null
+++ b/legacy-test/Android.mk
@@ -0,0 +1,29 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+# Build the legacy-test library
+# =============================
+# This contains the junit.framework classes that were in Android API level 25.
+include $(CLEAR_VARS)
+
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_STATIC_JAVA_LIBRARIES := core-junit-static
+
+LOCAL_MODULE := legacy-test
+
+include $(BUILD_JAVA_LIBRARY)
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
new file mode 100644
index 0000000..d501d25
--- /dev/null
+++ b/libs/androidfw/Android.bp
@@ -0,0 +1,74 @@
+// 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.
+
+// libandroidfw is partially built for the host (used by obbtool, aapt, and others)
+
+cc_library {
+    name: "libandroidfw",
+    host_supported: true,
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+    srcs: [
+        "Asset.cpp",
+        "AssetDir.cpp",
+        "AssetManager.cpp",
+        "AttributeResolution.cpp",
+        "LocaleData.cpp",
+        "misc.cpp",
+        "ObbFile.cpp",
+        "ResourceTypes.cpp",
+        "StreamingZipInflater.cpp",
+        "TypeWrappers.cpp",
+        "ZipFileRO.cpp",
+        "ZipUtils.cpp",
+    ],
+    export_include_dirs: ["include"],
+    target: {
+        android: {
+            srcs: [
+                "BackupData.cpp",
+                "BackupHelpers.cpp",
+                "CursorWindow.cpp",
+                "DisplayEventDispatcher.cpp",
+            ],
+            shared_libs: [
+                "libziparchive",
+                "libbase",
+                "libbinder",
+                "liblog",
+                "libcutils",
+                "libgui",
+                "libutils",
+                "libz",
+            ],
+            static: {
+                enabled: false,
+            },
+        },
+        host: {
+            cflags: ["-DSTATIC_ANDROIDFW_FOR_TOOLS"],
+            shared: {
+                enabled: false,
+            },
+            shared_libs: ["libz-host"],
+        },
+        windows: {
+            enabled: true,
+        },
+    },
+}
diff --git a/libs/androidfw/Android.mk b/libs/androidfw/Android.mk
index 7689256..68c51ef 100644
--- a/libs/androidfw/Android.mk
+++ b/libs/androidfw/Android.mk
@@ -14,74 +14,6 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-# libandroidfw is partially built for the host (used by obbtool, aapt, and others)
-# These files are common to host and target builds.
-
-commonSources := \
-    Asset.cpp \
-    AssetDir.cpp \
-    AssetManager.cpp \
-    AttributeResolution.cpp \
-    LocaleData.cpp \
-    misc.cpp \
-    ObbFile.cpp \
-    ResourceTypes.cpp \
-    StreamingZipInflater.cpp \
-    TypeWrappers.cpp \
-    ZipFileRO.cpp \
-    ZipUtils.cpp
-
-deviceSources := \
-    $(commonSources) \
-    BackupData.cpp \
-    BackupHelpers.cpp \
-    CursorWindow.cpp \
-    DisplayEventDispatcher.cpp
-
-hostSources := $(commonSources)
-
-# For the host
-# =====================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libandroidfw
-LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-LOCAL_SRC_FILES:= $(hostSources)
-LOCAL_C_INCLUDES := external/zlib
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-
-# For the device
-# =====================================================
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libandroidfw
-LOCAL_SRC_FILES:= $(deviceSources)
-LOCAL_C_INCLUDES := \
-    system/core/include
-LOCAL_SHARED_LIBRARIES := \
-    libziparchive \
-    libbase \
-    libbinder \
-    liblog \
-    libcutils \
-    libgui \
-    libutils \
-    libz
-
-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)
-
-
 # Include subdirectory makefiles
 # ============================================================
 
diff --git a/libs/androidfw/AttributeResolution.cpp b/libs/androidfw/AttributeResolution.cpp
index 00f7a42..d71fc39 100644
--- a/libs/androidfw/AttributeResolution.cpp
+++ b/libs/androidfw/AttributeResolution.cpp
@@ -193,9 +193,9 @@
   return true;
 }
 
-bool ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
-                uint32_t def_style_res, uint32_t* attrs, size_t attrs_length, uint32_t* out_values,
-                uint32_t* out_indices) {
+void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
+                uint32_t def_style_res, const uint32_t* attrs, size_t attrs_length,
+                uint32_t* out_values, uint32_t* out_indices) {
   if (kDebugStyles) {
     ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p", theme,
           def_style_attr, def_style_res, xml_parser);
@@ -376,7 +376,7 @@
     out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
     out_values[STYLE_DENSITY] = config.density;
 
-    if (out_indices != NULL && value.dataType != Res_value::TYPE_NULL) {
+    if (value.dataType != Res_value::TYPE_NULL) {
       indices_idx++;
       out_indices[indices_idx] = ii;
     }
@@ -386,10 +386,7 @@
 
   res.unlock();
 
-  if (out_indices != NULL) {
-    out_indices[0] = indices_idx;
-  }
-  return true;
+  out_indices[0] = indices_idx;
 }
 
 bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser, uint32_t* attrs,
diff --git a/libs/androidfw/include/androidfw/AttributeResolution.h b/libs/androidfw/include/androidfw/AttributeResolution.h
index 3ed8bce..8d5ff46 100644
--- a/libs/androidfw/include/androidfw/AttributeResolution.h
+++ b/libs/androidfw/include/androidfw/AttributeResolution.h
@@ -44,9 +44,9 @@
                   uint32_t* src_values, size_t src_values_length, uint32_t* attrs,
                   size_t attrs_length, uint32_t* out_values, uint32_t* out_indices);
 
-bool ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
-                uint32_t def_style_res, uint32_t* attrs, size_t attrs_length, uint32_t* out_values,
-                uint32_t* out_indices);
+void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
+                uint32_t def_style_res, const uint32_t* attrs, size_t attrs_length,
+                uint32_t* out_values, uint32_t* out_indices);
 
 bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser, uint32_t* attrs,
                         size_t attrs_length, uint32_t* out_values, uint32_t* out_indices);
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index 6837f25..d18cb8f 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -28,6 +28,7 @@
     Config_test.cpp \
     ConfigLocale_test.cpp \
     Idmap_test.cpp \
+    Main.cpp \
     ResTable_test.cpp \
     Split_test.cpp \
     TestHelpers.cpp \
@@ -59,7 +60,8 @@
     libutils \
     libcutils \
     liblog \
-    libz \
+    libz
+LOCAL_PICKUP_FILES := $(LOCAL_PATH)/data
 
 include $(BUILD_HOST_NATIVE_TEST)
 
@@ -80,7 +82,8 @@
     libbase \
     libcutils \
     libutils \
-    libui \
+    libui
+LOCAL_PICKUP_FILES := $(LOCAL_PATH)/data
 
 include $(BUILD_NATIVE_TEST)
 endif # Not SDK_ONLY
diff --git a/libs/androidfw/tests/AttributeResolution_test.cpp b/libs/androidfw/tests/AttributeResolution_test.cpp
index 7fbe6d3..3aac178 100644
--- a/libs/androidfw/tests/AttributeResolution_test.cpp
+++ b/libs/androidfw/tests/AttributeResolution_test.cpp
@@ -15,24 +15,27 @@
  */
 
 #include "androidfw/AttributeResolution.h"
+
+#include "android-base/file.h"
+#include "android-base/logging.h"
+#include "android-base/macros.h"
+
 #include "TestHelpers.h"
 #include "data/styles/R.h"
 
-#include <android-base/file.h>
-#include <android-base/macros.h>
-
-using namespace android;
-using android::base::ReadFileToString;
 using com::android::app::R;
 
+namespace android {
+
 class AttributeResolutionTest : public ::testing::Test {
  public:
   virtual void SetUp() override {
-    std::string test_source_dir = TestSourceDir();
+    std::string test_source_dir = GetTestDataPath();
     std::string contents;
-    LOG_ALWAYS_FATAL_IF(!ReadFileToString(test_source_dir + "/styles/resources.arsc", &contents));
-    LOG_ALWAYS_FATAL_IF(
-        table_.add(contents.data(), contents.size(), 1 /*cookie*/, true /*copyData*/) != NO_ERROR);
+    CHECK(base::ReadFileToString(test_source_dir + "/styles/resources.arsc",
+                                 &contents));
+    CHECK(table_.add(contents.data(), contents.size(), 1 /*cookie*/,
+                     true /*copyData*/) == NO_ERROR);
   }
 
  protected:
@@ -43,11 +46,12 @@
  public:
   virtual void SetUp() override {
     AttributeResolutionTest::SetUp();
-    std::string test_source_dir = TestSourceDir();
+    std::string test_source_dir = GetTestDataPath();
     std::string contents;
-    LOG_ALWAYS_FATAL_IF(!ReadFileToString(test_source_dir + "/styles/layout.xml", &contents));
-    LOG_ALWAYS_FATAL_IF(xml_parser_.setTo(contents.data(), contents.size(), true /*copyData*/) !=
-                        NO_ERROR);
+    CHECK(base::ReadFileToString(test_source_dir + "/styles/layout.xml",
+                                 &contents));
+    CHECK(xml_parser_.setTo(contents.data(), contents.size(),
+                            true /*copyData*/) == NO_ERROR);
 
     // Skip to the first tag.
     while (xml_parser_.next() != ResXMLParser::START_TAG) {
@@ -68,8 +72,9 @@
   values.resize(arraysize(attrs) * 6);
 
   ASSERT_TRUE(ResolveAttrs(&theme, 0 /*def_style_attr*/, 0 /*def_style_res*/,
-                           nullptr /*src_values*/, 0 /*src_values_length*/, attrs, arraysize(attrs),
-                           values.data(), nullptr /*out_indices*/));
+                           nullptr /*src_values*/, 0 /*src_values_length*/,
+                           attrs, arraysize(attrs), values.data(),
+                           nullptr /*out_indices*/));
 
   const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
 
@@ -111,8 +116,8 @@
   std::vector<uint32_t> values;
   values.resize(arraysize(attrs) * 6);
 
-  ASSERT_TRUE(RetrieveAttributes(&table_, &xml_parser_, attrs, arraysize(attrs), values.data(),
-                                 nullptr /*out_indices*/));
+  ASSERT_TRUE(RetrieveAttributes(&table_, &xml_parser_, attrs, arraysize(attrs),
+                                 values.data(), nullptr /*out_indices*/));
 
   uint32_t* values_cursor = values.data();
   EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
@@ -151,13 +156,14 @@
   ResTable::Theme theme(table_);
   ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo));
 
-  uint32_t attrs[] = {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four,
-                      R::attr::attr_five};
+  uint32_t attrs[] = {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
+                      R::attr::attr_four, R::attr::attr_five};
   std::vector<uint32_t> values;
   values.resize(arraysize(attrs) * 6);
 
-  ASSERT_TRUE(ApplyStyle(&theme, &xml_parser_, 0 /*def_style_attr*/, 0 /*def_style_res*/, attrs,
-                         arraysize(attrs), values.data(), nullptr /*out_indices*/));
+  ApplyStyle(&theme, &xml_parser_, 0 /*def_style_attr*/,
+             0 /*def_style_res*/, attrs, arraysize(attrs),
+             values.data(), nullptr /*out_indices*/);
 
   const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
 
@@ -199,3 +205,5 @@
   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
   EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
 }
+
+}  // namespace android
diff --git a/libs/androidfw/tests/Main.cpp b/libs/androidfw/tests/Main.cpp
new file mode 100644
index 0000000..6a50691
--- /dev/null
+++ b/libs/androidfw/tests/Main.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <libgen.h>
+
+#include <iostream>
+#include <memory>
+#include <string>
+
+#include "android-base/file.h"
+#include "android-base/strings.h"
+#include "gtest/gtest.h"
+
+#include "TestHelpers.h"
+
+// Extract the directory of the current executable path.
+static std::string GetExecutableDir() {
+  const std::string path = android::base::GetExecutablePath();
+  std::unique_ptr<char, decltype(&std::free)> mutable_path = {
+      strdup(path.c_str()), std::free};
+  std::string executable_dir = dirname(mutable_path.get());
+  return executable_dir;
+}
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+
+  // Set the default test data path to be the executable path directory.
+  android::SetTestDataPath(GetExecutableDir());
+
+  const char* command = argv[0];
+  ++argv;
+  --argc;
+
+  while (argc > 0) {
+    const std::string arg = *argv;
+    if (android::base::StartsWith(arg, "--testdata=")) {
+      android::SetTestDataPath(arg.substr(strlen("--testdata=")));
+    } else if (arg == "-h" || arg == "--help") {
+      std::cerr
+          << "\nAdditional options specific to this test:\n"
+             "  --testdata=[PATH]\n"
+             "      Specify the location of test data used within the tests.\n";
+      return 1;
+    } else {
+      std::cerr << command << ": Unrecognized argument '" << *argv << "'.\n";
+      return 1;
+    }
+
+    --argc;
+    ++argv;
+  }
+
+  std::cerr << "using --testdata=" << android::GetTestDataPath() << "\n";
+  return RUN_ALL_TESTS();
+}
diff --git a/libs/androidfw/tests/TestHelpers.cpp b/libs/androidfw/tests/TestHelpers.cpp
index 3d1d5f5..702ee5c 100644
--- a/libs/androidfw/tests/TestHelpers.cpp
+++ b/libs/androidfw/tests/TestHelpers.cpp
@@ -16,26 +16,23 @@
 
 #include "TestHelpers.h"
 
-#include <androidfw/ResourceTypes.h>
-#include <gtest/gtest.h>
 #include <unistd.h>
-#include <utils/String8.h>
 
-std::string TestSourceDir() {
-  const char* dir = getenv("ANDROID_BUILD_TOP");
-  LOG_ALWAYS_FATAL_IF(dir == nullptr, "Environment variable ANDROID_BUILD_TOP must be set");
-  std::string testdir = std::string(dir) + "/frameworks/base/libs/androidfw/tests/data";
-
-  // Check that the directory exists.
-  struct stat filestat;
-  LOG_ALWAYS_FATAL_IF(stat(testdir.c_str(), &filestat) != 0, "test data path '%s' does not exist",
-                      testdir.c_str());
-  return testdir;
-}
+#include "android-base/logging.h"
 
 namespace android {
 
-::testing::AssertionResult IsStringEqual(const ResTable& table, uint32_t resource_id,
+static std::string sTestDataPath;
+
+void SetTestDataPath(const std::string& path) { sTestDataPath = path; }
+
+const std::string& GetTestDataPath() {
+  CHECK(!sTestDataPath.empty()) << "no test data path set.";
+  return sTestDataPath;
+}
+
+::testing::AssertionResult IsStringEqual(const ResTable& table,
+                                         uint32_t resource_id,
                                          const char* expected_str) {
   Res_value val;
   ssize_t block = table.getResource(resource_id, &val, MAY_NOT_BE_BAG);
@@ -49,7 +46,8 @@
 
   const ResStringPool* pool = table.getTableStringBlock(block);
   if (pool == NULL) {
-    return ::testing::AssertionFailure() << "table has no string pool for block " << block;
+    return ::testing::AssertionFailure()
+           << "table has no string pool for block " << block;
   }
 
   const String8 actual_str = pool->string8ObjectAt(val.data);
diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h
index 5f0c4552..c1e349f 100644
--- a/libs/androidfw/tests/TestHelpers.h
+++ b/libs/androidfw/tests/TestHelpers.h
@@ -14,24 +14,24 @@
  * limitations under the License.
  */
 
-#ifndef __TEST_HELPERS_H
-#define __TEST_HELPERS_H
-
-#include <androidfw/ResourceTypes.h>
-#include <gtest/gtest.h>
-#include <utils/String16.h>
-#include <utils/String8.h>
+#ifndef TEST_HELPERS_H_
+#define TEST_HELPERS_H_
 
 #include <ostream>
 #include <string>
 
-std::string TestSourceDir();
+#include "androidfw/ResourceTypes.h"
+#include "gtest/gtest.h"
+#include "utils/String16.h"
+#include "utils/String8.h"
 
-static inline ::std::ostream& operator<<(::std::ostream& out, const android::String8& str) {
+static inline ::std::ostream& operator<<(::std::ostream& out,
+                                         const android::String8& str) {
   return out << str.string();
 }
 
-static inline ::std::ostream& operator<<(::std::ostream& out, const android::String16& str) {
+static inline ::std::ostream& operator<<(::std::ostream& out,
+                                         const android::String16& str) {
   return out << android::String8(str).string();
 }
 
@@ -39,18 +39,24 @@
 
 enum { MAY_NOT_BE_BAG = false };
 
-static inline bool operator==(const android::ResTable_config& a,
-                              const android::ResTable_config& b) {
+void SetTestDataPath(const std::string& path);
+
+const std::string& GetTestDataPath();
+
+static inline bool operator==(const ResTable_config& a,
+                              const ResTable_config& b) {
   return a.compare(b) == 0;
 }
 
-static inline ::std::ostream& operator<<(::std::ostream& out, const android::ResTable_config& c) {
+static inline ::std::ostream& operator<<(::std::ostream& out,
+                                         const ResTable_config& c) {
   return out << c.toString().string();
 }
 
-::testing::AssertionResult IsStringEqual(const ResTable& table, uint32_t resource_id,
+::testing::AssertionResult IsStringEqual(const ResTable& table,
+                                         uint32_t resource_id,
                                          const char* expected_str);
 
 }  // namespace android
 
-#endif  // __TEST_HELPERS_H
+#endif  // TEST_HELPERS_H_
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index eff2499..cf571e9 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -278,6 +278,7 @@
     tests/unit/BakedOpDispatcherTests.cpp \
     tests/unit/BakedOpRendererTests.cpp \
     tests/unit/BakedOpStateTests.cpp \
+    tests/unit/BitmapTests.cpp \
     tests/unit/CanvasContextTests.cpp \
     tests/unit/CanvasStateTests.cpp \
     tests/unit/ClipAreaTests.cpp \
@@ -297,6 +298,7 @@
     tests/unit/MeshStateTests.cpp \
     tests/unit/OffscreenBufferPoolTests.cpp \
     tests/unit/OpDumperTests.cpp \
+    tests/unit/PathInterpolatorTests.cpp \
     tests/unit/RenderNodeDrawableTests.cpp \
     tests/unit/RecordingCanvasTests.cpp \
     tests/unit/RenderNodeTests.cpp \
diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp
index 1d67579..00238a2 100644
--- a/libs/hwui/Extensions.cpp
+++ b/libs/hwui/Extensions.cpp
@@ -37,6 +37,26 @@
 
 
 Extensions::Extensions() {
+    const char* version = (const char*) glGetString(GL_VERSION);
+
+    // Section 6.1.5 of the OpenGL ES specification indicates the GL version
+    // string strictly follows this format:
+    //
+    // OpenGL<space>ES<space><version number><space><vendor-specific information>
+    //
+    // In addition section 6.1.5 describes the version number thusly:
+    //
+    // "The version number is either of the form major number.minor number or
+    // major number.minor number.release number, where the numbers all have one
+    // or more digits. The release number and vendor specific information are
+    // optional."
+
+    if (sscanf(version, "OpenGL ES %d.%d", &mVersionMajor, &mVersionMinor) != 2) {
+        // If we cannot parse the version number, assume OpenGL ES 2.0
+        mVersionMajor = 2;
+        mVersionMinor = 0;
+    }
+
     auto extensions = StringUtils::split((const char*) glGetString(GL_EXTENSIONS));
     mHasNPot = extensions.has("GL_OES_texture_npot");
     mHasFramebufferFetch = extensions.has("GL_NV_shader_framebuffer_fetch");
@@ -58,26 +78,6 @@
     mHasSRGB = false;
     mHasSRGBWriteControl = false;
 #endif
-
-    const char* version = (const char*) glGetString(GL_VERSION);
-
-    // Section 6.1.5 of the OpenGL ES specification indicates the GL version
-    // string strictly follows this format:
-    //
-    // OpenGL<space>ES<space><version number><space><vendor-specific information>
-    //
-    // In addition section 6.1.5 describes the version number thusly:
-    //
-    // "The version number is either of the form major number.minor number or
-    // major number.minor number.release number, where the numbers all have one
-    // or more digits. The release number and vendor specific information are
-    // optional."
-
-    if (sscanf(version, "OpenGL ES %d.%d", &mVersionMajor, &mVersionMinor) != 2) {
-        // If we cannot parse the version number, assume OpenGL ES 2.0
-        mVersionMajor = 2;
-        mVersionMinor = 0;
-    }
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Interpolator.cpp b/libs/hwui/Interpolator.cpp
index cc47f00..f94a22d 100644
--- a/libs/hwui/Interpolator.cpp
+++ b/libs/hwui/Interpolator.cpp
@@ -88,6 +88,39 @@
     return t * t * ((mTension + 1) * t + mTension) + 1.0f;
 }
 
+float PathInterpolator::interpolate(float t) {
+    if (t <= 0) {
+        return 0;
+    } else if (t >= 1) {
+        return 1;
+    }
+    // Do a binary search for the correct x to interpolate between.
+    size_t startIndex = 0;
+    size_t endIndex = mX.size() - 1;
+
+    while (endIndex > startIndex + 1) {
+        int midIndex = (startIndex + endIndex) / 2;
+        if (t < mX[midIndex]) {
+            endIndex = midIndex;
+        } else {
+            startIndex = midIndex;
+        }
+    }
+
+    float xRange = mX[endIndex] - mX[startIndex];
+    if (xRange == 0) {
+        return mY[startIndex];
+    }
+
+    float tInRange = t - mX[startIndex];
+    float fraction = tInRange / xRange;
+
+    float startY = mY[startIndex];
+    float endY = mY[endIndex];
+    return startY + (fraction * (endY - startY));
+
+}
+
 LUTInterpolator::LUTInterpolator(float* values, size_t size)
     : mValues(values)
     , mSize(size) {
@@ -97,7 +130,8 @@
 }
 
 float LUTInterpolator::interpolate(float input) {
-    float lutpos = input * mSize;
+    // lut position should only be at the end of the table when input is 1f.
+    float lutpos = input * (mSize - 1);
     if (lutpos >= (mSize - 1)) {
         return mValues[mSize - 1];
     }
diff --git a/libs/hwui/Interpolator.h b/libs/hwui/Interpolator.h
index 6512008..224cee7 100644
--- a/libs/hwui/Interpolator.h
+++ b/libs/hwui/Interpolator.h
@@ -20,6 +20,7 @@
 #include <memory>
 
 #include <cutils/compiler.h>
+#include <vector>
 
 namespace android {
 namespace uirenderer {
@@ -100,6 +101,16 @@
     const float mTension;
 };
 
+class ANDROID_API PathInterpolator : public Interpolator {
+public:
+    explicit PathInterpolator(std::vector<float>&& x, std::vector<float>&& y)
+            : mX (x), mY(y) {}
+    virtual float interpolate(float input) override;
+private:
+    std::vector<float> mX;
+    std::vector<float> mY;
+};
+
 class ANDROID_API LUTInterpolator : public Interpolator {
 public:
     LUTInterpolator(float* values, size_t size);
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index a03ded6..a5443d9 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -188,8 +188,9 @@
     ATRACE_CALL();
     LOG_ALWAYS_FATAL_IF(!info.damageAccumulator, "DamageAccumulator missing");
 
-    // Functors don't correctly handle stencil usage of overdraw debugging - shove 'em in a layer.
-    bool functorsNeedLayer = Properties::debugOverdraw;
+    // The OpenGL renderer reserves the stencil buffer for overdraw debugging.  Functors
+    // will need to be drawn in a layer.
+    bool functorsNeedLayer = Properties::debugOverdraw && !Properties::isSkiaEnabled();
 
     prepareTreeImpl(info, functorsNeedLayer);
 }
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 97b7dd7..f4ffa7a 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -574,7 +574,7 @@
 }
 
 bool Tree::canReuseBitmap(Bitmap* bitmap, int width, int height) {
-    return bitmap && width == bitmap->width() && height == bitmap->height();
+    return bitmap && width <= bitmap->width() && height <= bitmap->height();
 }
 
 void Tree::onPropertyChanged(TreeProperties* prop) {
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index e9a9c71..8244a39 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -630,10 +630,15 @@
         }
 
         void setScaledSize(int width, int height) {
-            if (mNonAnimatableProperties.scaledWidth != width
-                    || mNonAnimatableProperties.scaledHeight != height) {
-                mNonAnimatableProperties.scaledWidth = width;
-                mNonAnimatableProperties.scaledHeight = height;
+            // If the requested size is bigger than what the bitmap was, then
+            // we increase the bitmap size to match. The width and height
+            // are bound by MAX_CACHED_BITMAP_SIZE.
+            if (mNonAnimatableProperties.scaledWidth < width
+                    || mNonAnimatableProperties.scaledHeight < height) {
+                mNonAnimatableProperties.scaledWidth = std::max(width,
+                        mNonAnimatableProperties.scaledWidth);
+                mNonAnimatableProperties.scaledHeight = std::max(height,
+                        mNonAnimatableProperties.scaledHeight);
                 mNonAnimatablePropertiesDirty = true;
                 mTree->onPropertyChanged(this);
             }
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index d6b6548..d3e765d 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -246,7 +246,7 @@
     if (!uploadBitmapToGraphicBuffer(caches, bitmap, *buffer, format, type)) {
         return nullptr;
     }
-    return sk_sp<Bitmap>(new Bitmap(std::move(buffer), info));
+    return sk_sp<Bitmap>(new Bitmap(buffer.get(), info));
 }
 
 sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(SkBitmap& bitmap) {
@@ -301,6 +301,16 @@
             info, pixelRef.rowBytes(), pixelRef.colorTable()));
 }
 
+sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer) {
+    PixelFormat format = graphicBuffer->getPixelFormat();
+    if (!graphicBuffer.get() || format != PIXEL_FORMAT_RGBA_8888) {
+        return nullptr;
+    }
+    SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
+            kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+    return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info));
+}
+
 void Bitmap::reconfigure(const SkImageInfo& newInfo, size_t rowBytes, SkColorTable* ctable) {
     if (kIndex_8_SkColorType != newInfo.colorType()) {
         ctable = nullptr;
@@ -360,16 +370,14 @@
     reconfigure(info, rowBytes, ctable);
 }
 
-Bitmap::Bitmap(sp<GraphicBuffer>&& buffer, const SkImageInfo& info)
+Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info)
         : SkPixelRef(info)
         , mPixelStorageType(PixelStorageType::Hardware) {
-    auto rawBuffer = buffer.get();
-    mPixelStorage.hardware.buffer = rawBuffer;
-    if (rawBuffer) {
-        rawBuffer->incStrong(rawBuffer);
-    }
+    mPixelStorage.hardware.buffer = buffer;
+    buffer->incStrong(buffer);
     mRowBytes = bytesPerPixel(buffer->getPixelFormat()) * buffer->getStride();
 }
+
 Bitmap::~Bitmap() {
     switch (mPixelStorageType) {
     case PixelStorageType::External:
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 663238c..518be03 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -52,6 +52,8 @@
     static sk_sp<Bitmap> allocateAshmemBitmap(size_t allocSize, const SkImageInfo& info,
         size_t rowBytes, SkColorTable* ctable);
 
+    static sk_sp<Bitmap> createFrom(sp<GraphicBuffer> graphicBuffer);
+
     static sk_sp<Bitmap> createFrom(const SkImageInfo&, SkPixelRef&);
 
     static sk_sp<Bitmap> allocateHardwareBitmap(uirenderer::renderthread::RenderThread&,
@@ -63,7 +65,6 @@
             const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable);
     Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info,
             size_t rowBytes, SkColorTable* ctable);
-    Bitmap(sp<GraphicBuffer>&& buffer, const SkImageInfo& info);
 
     int width() const { return info().width(); }
     int height() const { return info().height(); }
@@ -113,6 +114,7 @@
     virtual void onUnlockPixels() override { };
     virtual size_t getAllocatedSizeInBytes() const override;
 private:
+    Bitmap(GraphicBuffer* buffer, const SkImageInfo& info);
     virtual ~Bitmap();
     void* getStorage() const;
 
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index da9002d..4b34c7c 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -174,13 +174,22 @@
             }
             renderNode->getLayerSurface()->draw(canvas, 0, 0, paint);
 
-            if (CC_UNLIKELY(Properties::debugLayersUpdates
-                    && !renderNode->getSkiaLayer()->hasRenderedSinceRepaint)) {
+            if (!renderNode->getSkiaLayer()->hasRenderedSinceRepaint) {
                 renderNode->getSkiaLayer()->hasRenderedSinceRepaint = true;
-                SkPaint layerPaint;
-                layerPaint.setColor(0x7f00ff00);
-                canvas->drawRect(bounds, layerPaint);
+                if (CC_UNLIKELY(Properties::debugLayersUpdates)) {
+                    SkPaint layerPaint;
+                    layerPaint.setColor(0x7f00ff00);
+                    canvas->drawRect(bounds, layerPaint);
+                } else if (CC_UNLIKELY(Properties::debugOverdraw)) {
+                    // Render transparent rect to increment overdraw for repaint area.
+                    // This can be "else if" because flashing green on layer updates
+                    // will also increment the overdraw if it happens to be turned on.
+                    SkPaint transparentPaint;
+                    transparentPaint.setColor(SK_ColorTRANSPARENT);
+                    canvas->drawRect(bounds, transparentPaint);
+                }
             }
+
         // composing a software layer with alpha
         } else if (properties.effectiveLayerType() == LayerType::Software) {
             SkPaint paint;
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
index 6973209..d05e7f6 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
@@ -40,7 +40,7 @@
         //mChildren is allocated and initialized only the first time onDraw is called and cached for
         //subsequent calls
         mChildren.reserve(mEndChildIndex - mBeginChildIndex + 1);
-        for (unsigned int i = mBeginChildIndex; i <= mEndChildIndex; i++) {
+        for (int i = mBeginChildIndex; i <= mEndChildIndex; i++) {
             mChildren.push_back(const_cast<RenderNodeDrawable*>(&mDisplayList->mChildNodes[i]));
         }
     }
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
index 298a732..9f00d23 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
@@ -47,8 +47,8 @@
     virtual void onDraw(SkCanvas* canvas) override;
 
 private:
-    size_t mEndChildIndex;
-    size_t mBeginChildIndex;
+    int mEndChildIndex;
+    int mBeginChildIndex;
     FatVector<RenderNodeDrawable*, 16> mChildren;
     SkiaDisplayList* mDisplayList;
 
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index c5a40d4..0f2d09d 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -18,6 +18,8 @@
 
 #include "utils/TraceUtils.h"
 #include <SkOSFile.h>
+#include <SkOverdrawCanvas.h>
+#include <SkOverdrawColorFilter.h>
 #include <SkPicture.h>
 #include <SkPictureRecorder.h>
 #include <SkPixelSerializer.h>
@@ -192,6 +194,34 @@
         }
     }
 
+    renderFrameImpl(layers, clip, nodes, opaque, contentDrawBounds, canvas);
+
+    if (skpCaptureEnabled() && recordingPicture) {
+        sk_sp<SkPicture> picture = recorder->finishRecordingAsPicture();
+        if (picture->approximateOpCount() > 0) {
+            SkFILEWStream stream(prop);
+            if (stream.isValid()) {
+                PngPixelSerializer serializer;
+                picture->serialize(&stream, &serializer);
+                stream.flush();
+                SkDebugf("Captured Drawing Output (%d bytes) for frame. %s", stream.bytesWritten(), prop);
+            }
+        }
+        surface->getCanvas()->drawPicture(picture);
+    }
+
+    if (CC_UNLIKELY(Properties::debugOverdraw)) {
+        renderOverdraw(layers, clip, nodes, contentDrawBounds, surface);
+    }
+
+    ATRACE_NAME("flush commands");
+    canvas->flush();
+}
+
+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, SkRegion::kReplace_Op);
 
     if (!opaque) {
@@ -250,23 +280,6 @@
         canvas->restoreToCount(count);
         layer++;
     }
-
-    if (skpCaptureEnabled() && recordingPicture) {
-        sk_sp<SkPicture> picture = recorder->finishRecordingAsPicture();
-        if (picture->approximateOpCount() > 0) {
-            SkFILEWStream stream(prop);
-            if (stream.isValid()) {
-                PngPixelSerializer serializer;
-                picture->serialize(&stream, &serializer);
-                stream.flush();
-                SkDebugf("Captured Drawing Output (%d bytes) for frame. %s", stream.bytesWritten(), prop);
-            }
-        }
-        surface->getCanvas()->drawPicture(picture);
-    }
-
-    ATRACE_NAME("flush commands");
-    canvas->flush();
 }
 
 void SkiaPipeline::dumpResourceCacheUsage() const {
@@ -283,6 +296,40 @@
     ALOGD("%s", log.c_str());
 }
 
+// Overdraw debugging
+
+// These colors should be kept in sync with Caches::getOverdrawColor() with a few differences.
+// This implementation:
+// (1) Requires transparent entries for "no overdraw" and "single draws".
+// (2) Requires premul colors (instead of unpremul).
+// (3) Requires RGBA colors (instead of BGRA).
+static const uint32_t kOverdrawColors[2][6] = {
+        { 0x00000000, 0x00000000, 0x2f2f0000, 0x2f002f00, 0x3f00003f, 0x7f00007f, },
+        { 0x00000000, 0x00000000, 0x2f2f0000, 0x4f004f4f, 0x5f50335f, 0x7f00007f, },
+};
+
+void SkiaPipeline::renderOverdraw(const LayerUpdateQueue& layers, const SkRect& clip,
+        const std::vector<sp<RenderNode>>& nodes, const Rect &contentDrawBounds,
+        sk_sp<SkSurface> surface) {
+    // Set up the overdraw canvas.
+    SkImageInfo offscreenInfo = SkImageInfo::MakeA8(surface->width(), surface->height());
+    sk_sp<SkSurface> offscreen = surface->makeSurface(offscreenInfo);
+    SkOverdrawCanvas overdrawCanvas(offscreen->getCanvas());
+
+    // Fake a redraw to replay the draw commands.  This will increment the alpha channel
+    // each time a pixel would have been drawn.
+    // Pass true for opaque so we skip the clear - the overdrawCanvas is already zero
+    // initialized.
+    renderFrameImpl(layers, clip, nodes, true, contentDrawBounds, &overdrawCanvas);
+    sk_sp<SkImage> counts = offscreen->makeImageSnapshot();
+
+    // Draw overdraw colors to the canvas.  The color filter will convert counts to colors.
+    SkPaint paint;
+    const SkPMColor* colors = kOverdrawColors[static_cast<int>(Properties::overdrawColorSet)];
+    paint.setColorFilter(SkOverdrawColorFilter::Make(colors));
+    surface->getCanvas()->drawImage(counts.get(), 0.0f, 0.0f, &paint);
+}
+
 } /* namespace skiapipeline */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index c1c8cbe..c58fedf 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -107,6 +107,18 @@
     renderthread::RenderThread& mRenderThread;
 
 private:
+    void renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
+            const std::vector< sp<RenderNode> >& nodes, bool opaque, const Rect &contentDrawBounds,
+            SkCanvas* canvas);
+
+    /**
+     *  Debugging feature.  Draws a semi-transparent overlay on each pixel, indicating
+     *  how many times it has been drawn.
+     */
+    void renderOverdraw(const LayerUpdateQueue& layers, const SkRect& clip,
+            const std::vector< sp<RenderNode> >& nodes, const Rect &contentDrawBounds,
+            sk_sp<SkSurface>);
+
     TaskManager mTaskManager;
     std::vector<sk_sp<SkImage>> mPinnedImages;
     static float mLightRadius;
diff --git a/libs/hwui/tests/unit/BitmapTests.cpp b/libs/hwui/tests/unit/BitmapTests.cpp
new file mode 100644
index 0000000..8c7e081
--- /dev/null
+++ b/libs/hwui/tests/unit/BitmapTests.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "hwui/Bitmap.h"
+
+#include <SkBitmap.h>
+#include <SkColorTable.h>
+#include <SkImageInfo.h>
+
+#include <tests/common/TestUtils.h>
+
+using namespace android;
+using namespace android::uirenderer;
+
+TEST(Bitmap, colorTableRefCounting) {
+    const SkPMColor c[] = { SkPackARGB32(0x80, 0x80, 0, 0) };
+    SkColorTable* ctable = new SkColorTable(c, SK_ARRAY_COUNT(c));
+
+    SkBitmap* bm = new SkBitmap();
+    bm->allocPixels(SkImageInfo::Make(1, 1, kIndex_8_SkColorType, kPremul_SkAlphaType),
+            nullptr, ctable);
+    sk_sp<Bitmap> bitmap = Bitmap::allocateHeapBitmap(bm, ctable);
+    EXPECT_FALSE(ctable->unique());
+    delete bm;
+    bitmap.reset();
+    EXPECT_TRUE(ctable->unique());
+    ctable->unref();
+}
+
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index 950b2c4..a1c225f 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -1530,6 +1530,8 @@
 RENDERTHREAD_TEST(FrameBuilder, zReorder) {
     auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
             [](RenderProperties& props, RecordingCanvas& canvas) {
+        canvas.insertReorderBarrier(true);
+        canvas.insertReorderBarrier(false);
         drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
         drawOrderedRect(&canvas, 1);
         canvas.insertReorderBarrier(true);
diff --git a/libs/hwui/tests/unit/PathInterpolatorTests.cpp b/libs/hwui/tests/unit/PathInterpolatorTests.cpp
new file mode 100644
index 0000000..d7cb23a
--- /dev/null
+++ b/libs/hwui/tests/unit/PathInterpolatorTests.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <gtest/gtest.h>
+
+#include <Interpolator.h>
+
+namespace android {
+namespace uirenderer {
+
+struct TestData {
+    const std::vector<float> x;
+    const std::vector<float> y;
+    const std::vector<float> inFraction;
+    const std::vector<float> outFraction;
+};
+
+const static TestData sTestDataSet[] = {
+        {
+                // Straight line as a path.
+                {0.0f, 1.0f},
+                {0.0f, 1.0f},
+                {0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f},
+                {0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f},
+        },
+
+        {
+                {
+                        0.0f, 0.5f, 0.5178955f, 0.5341797f, 0.5489991f, 0.5625f, 0.5748291f,
+                        0.5861328f, 0.60625005f, 0.62402344f, 0.640625f, 0.675f, 0.6951172f,
+                        0.71875f, 0.7470703f, 0.78125f, 0.82246095f, 0.84606934f, 0.871875f,
+                        0.9000244f, 0.93066406f, 0.96394044f, 1.0f
+                },
+                {
+                        0.0f, 0.0f, 0.0028686523f, 0.011230469f, 0.024719238f, 0.04296875f,
+                        0.06561279f, 0.092285156f, 0.15625f, 0.2319336f, 0.31640625f, 0.5f,
+                        0.5932617f, 0.68359375f, 0.7680664f, 0.84375f, 0.90771484f, 0.9343872f,
+                        0.95703125f, 0.97528076f, 0.98876953f, 0.99713135f, 1.0f
+                },
+                {
+                        0.0f, 0.03375840187072754f, 0.13503384590148926f, 0.23630905151367188f,
+                        0.336834192276001f, 0.4508626461029053f, 0.564141035079956f,
+                        0.6781694889068604f, 0.7921979427337646f, 0.9054763317108154f, 1.0f
+                },
+                {
+                        0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0459827296435833f,
+                        0.5146934390068054f, 0.8607426285743713f, 0.9776809215545654f, 1.0f
+
+                }
+
+        },
+        {
+                {
+                        0.0f, 0.017895509f, 0.034179688f, 0.048999026f, 0.0625f, 0.0748291f,
+                        0.08613282f, 0.10625f, 0.12402344f, 0.140625f, 0.17500001f, 0.19511719f,
+                        0.21875f, 0.24707031f, 0.28125f, 0.32246095f, 0.34606934f, 0.371875f,
+                        0.4000244f, 0.43066406f, 0.46394044f, 0.5f, 1.0f
+                },
+                {
+                        0.0f, 0.0028686523f, 0.011230469f, 0.024719238f, 0.04296875f, 0.06561279f,
+                        0.092285156f, 0.15625f, 0.2319336f, 0.31640625f, 0.5f, 0.5932617f,
+                        0.68359375f, 0.7680664f, 0.84375f, 0.90771484f, 0.9343872f, 0.95703125f,
+                        0.97528076f, 0.98876953f, 0.99713135f, 1.0f, 1.0f
+                },
+                {
+                        0.0f, 0.102020263671875f, 0.20330810546875f, 0.3165740966796875f,
+                        0.43060302734375f, 0.5318756103515625f, 0.6331634521484375f,
+                        0.746429443359375f, 0.84771728515625f, 0.9617462158203125f, 1.0f
+                },
+                {
+                        0.0f, 0.14280107617378235f, 0.6245699524879456f, 0.8985776901245117f,
+                        0.9887426495552063f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
+                }
+        },
+
+
+};
+
+static std::vector<float> getX(const TestData& data) {
+    return data.x;
+}
+
+static std::vector<float> getY(const TestData& data) {
+    return data.y;
+}
+
+TEST(Interpolator, pathInterpolation) {
+    for (const TestData& data: sTestDataSet) {
+        PathInterpolator interpolator(getX(data), getY(data));
+        for (size_t i = 0; i < data.inFraction.size(); i++) {
+            EXPECT_FLOAT_EQ(data.outFraction[i], interpolator.interpolate(data.inFraction[i]));
+        }
+    }
+}
+
+}
+}
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index c2df9ec..f4b686d 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -102,6 +102,8 @@
 
     auto parent = TestUtils::createSkiaNode(0, 0, 100, 100,
             [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+        canvas.insertReorderBarrier(true);
+        canvas.insertReorderBarrier(false);
         drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
         drawOrderedRect(&canvas, 1);
         canvas.insertReorderBarrier(true);
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 7a2fa57..17801af 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -179,3 +179,53 @@
     redNode->setLayerSurface(sk_sp<SkSurface>());
     blueNode->setLayerSurface(sk_sp<SkSurface>());
 }
+
+RENDERTHREAD_TEST(SkiaPipeline, renderOverdraw) {
+    ScopedProperty<bool> prop(Properties::debugOverdraw, true);
+
+    auto whiteNode = TestUtils::createSkiaNode(0, 0, 1, 1,
+        [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+            canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
+        });
+    LayerUpdateQueue layerUpdateQueue;
+    SkRect dirty = SkRect::MakeXYWH(0, 0, 1, 1);
+    std::vector<sp<RenderNode>> renderNodes;
+    renderNodes.push_back(whiteNode);
+    bool opaque = true;
+    android::uirenderer::Rect contentDrawBounds(0, 0, 1, 1);
+    auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
+    auto surface = SkSurface::MakeRasterN32Premul(1, 1);
+
+    // Initialize the canvas to blue.
+    surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
+    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
+
+    // Single draw, should be white.
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE);
+
+    // 1 Overdraw, should be blue blended onto white.
+    renderNodes.push_back(whiteNode);
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffd0d0ff);
+
+    // 2 Overdraw, should be green blended onto white
+    renderNodes.push_back(whiteNode);
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffd0ffd0);
+
+    // 3 Overdraw, should be pink blended onto white.
+    renderNodes.push_back(whiteNode);
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffffc0c0);
+
+    // 4 Overdraw, should be red blended onto white.
+    renderNodes.push_back(whiteNode);
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffff8080);
+
+    // 5 Overdraw, should be red blended onto white.
+    renderNodes.push_back(whiteNode);
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffff8080);
+}
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index 93e86af..4c39c30 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -131,14 +131,11 @@
         public String text;
         public int requestorIdEncoding;
         public int textEncoding;
-        public Bundle extras;
     };
 
     public static class GpsNiResponse {
         /* User response, one of the values in GpsUserResponseType */
         int userResponse;
-        /* Optional extra data to pass with the user response */
-        Bundle extras;
     };
 
     private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() {
diff --git a/media/java/android/media/AsyncPlayer.java b/media/java/android/media/AsyncPlayer.java
index dd5f6ba..c1a178a 100644
--- a/media/java/android/media/AsyncPlayer.java
+++ b/media/java/android/media/AsyncPlayer.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.media.PlayerBase;
 import android.net.Uri;
 import android.os.PowerManager;
 import android.os.SystemClock;
@@ -163,6 +164,7 @@
      * @deprecated use {@link #play(Context, Uri, boolean, AudioAttributes)} instead
      */
     public void play(Context context, Uri uri, boolean looping, int stream) {
+        PlayerBase.deprecateStreamTypeForPlayback(stream, "AsyncPlayer", "play()");
         if (context == null || uri == null) {
             return;
         }
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 43fb4b9..16b3315 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -359,6 +359,9 @@
      *   for an AudioTrack instance in streaming mode.
      * @param mode streaming or static buffer. See {@link #MODE_STATIC} and {@link #MODE_STREAM}
      * @throws java.lang.IllegalArgumentException
+     * @deprecated use {@link Builder} or
+     *   {@link #AudioTrack(AudioAttributes, AudioFormat, int, int, int)} to specify the
+     *   {@link AudioAttributes} instead of the stream type which is only for volume control.
      */
     public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
             int bufferSizeInBytes, int mode)
@@ -414,6 +417,9 @@
      * @param mode streaming or static buffer. See {@link #MODE_STATIC} and {@link #MODE_STREAM}
      * @param sessionId Id of audio session the AudioTrack must be attached to
      * @throws java.lang.IllegalArgumentException
+     * @deprecated use {@link Builder} or
+     *   {@link #AudioTrack(AudioAttributes, AudioFormat, int, int, int)} to specify the
+     *   {@link AudioAttributes} instead of the stream type which is only for volume control.
      */
     public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
             int bufferSizeInBytes, int mode, int sessionId)
@@ -429,6 +435,7 @@
                     .build(),
                 bufferSizeInBytes,
                 mode, sessionId);
+        deprecateStreamTypeForPlayback(streamType, "AudioTrack", "AudioTrack()");
     }
 
     /**
@@ -1044,11 +1051,12 @@
     }
 
     /**
-     * Returns the type of audio stream this AudioTrack is configured for.
+     * Returns the volume stream type of this AudioTrack.
      * Compare the result against {@link AudioManager#STREAM_VOICE_CALL},
      * {@link AudioManager#STREAM_SYSTEM}, {@link AudioManager#STREAM_RING},
      * {@link AudioManager#STREAM_MUSIC}, {@link AudioManager#STREAM_ALARM},
-     * {@link AudioManager#STREAM_NOTIFICATION}, or {@link AudioManager#STREAM_DTMF}.
+     * {@link AudioManager#STREAM_NOTIFICATION}, {@link AudioManager#STREAM_DTMF} or
+     * {@link AudioManager#STREAM_ACCESSIBILITY}.
      */
     public int getStreamType() {
         return mStreamType;
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index bbb7184..52d5b7ca 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -2765,23 +2765,28 @@
                         tag != null ? tag.name : null, dataFormat, numberOfComponents));
             }
 
-            if (tag == null || dataFormat <= 0 ||
-                    dataFormat >= IFD_FORMAT_BYTES_PER_FORMAT.length) {
-                // Skip if the parsed tag number is not defined or invalid data format.
-                if (DEBUG) {
-                    if (tag == null) {
-                        Log.w(TAG, "Skip tag entry since tag number is not defined: " + tagNumber);
-                    } else {
-                        Log.w(TAG, "Skip tag entry since data format is invalid: " + dataFormat);
-                    }
+            long byteCount = 0;
+            boolean valid = false;
+            if (tag == null) {
+                Log.w(TAG, "Skip the tag entry since tag number is not defined: " + tagNumber);
+            } else if (dataFormat <= 0 || dataFormat >= IFD_FORMAT_BYTES_PER_FORMAT.length) {
+                Log.w(TAG, "Skip the tag entry since data format is invalid: " + dataFormat);
+            } else {
+                byteCount = (long) numberOfComponents * IFD_FORMAT_BYTES_PER_FORMAT[dataFormat];
+                if (byteCount < 0 || byteCount > Integer.MAX_VALUE) {
+                    Log.w(TAG, "Skip the tag entry since the number of components is invalid: "
+                            + numberOfComponents);
+                } else {
+                    valid = true;
                 }
+            }
+            if (!valid) {
                 dataInputStream.seek(nextEntryOffset);
                 continue;
             }
 
             // Read a value from data field or seek to the value offset which is stored in data
             // field if the size of the entry value is bigger than 4.
-            int byteCount = numberOfComponents * IFD_FORMAT_BYTES_PER_FORMAT[dataFormat];
             if (byteCount > 4) {
                 int offset = dataInputStream.readInt();
                 if (DEBUG) {
@@ -2871,7 +2876,7 @@
                 continue;
             }
 
-            byte[] bytes = new byte[byteCount];
+            byte[] bytes = new byte[(int) byteCount];
             dataInputStream.readFully(bytes);
             ExifAttribute attribute = new ExifAttribute(dataFormat, numberOfComponents, bytes);
             mAttributes[ifdType].put(tag.name, attribute);
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 36ad90b..78da59c 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -124,10 +124,10 @@
  *         is called. It is a programming error to invoke methods such
  *         as {@link #getCurrentPosition()},
  *         {@link #getDuration()}, {@link #getVideoHeight()},
- *         {@link #getVideoWidth()}, {@link #setAudioStreamType(int)},
+ *         {@link #getVideoWidth()}, {@link #setAudioAttributes(AudioAttributes)},
  *         {@link #setLooping(boolean)},
  *         {@link #setVolume(float, float)}, {@link #pause()}, {@link #start()},
- *         {@link #stop()}, {@link #seekTo(int)}, {@link #prepare()} or
+ *         {@link #stop()}, {@link #seekTo(int, int)}, {@link #prepare()} or
  *         {@link #prepareAsync()} in the <em>Idle</em> state for both cases. If any of these
  *         methods is called right after a MediaPlayer object is constructed,
  *         the user supplied callback method OnErrorListener.onError() won't be
@@ -273,19 +273,22 @@
  *         </ul>
  *         </li>
  *     <li>The playback position can be adjusted with a call to
- *         {@link #seekTo(int)}.
+ *         {@link #seekTo(int, int)}.
  *         <ul>
- *         <li>Although the asynchronuous {@link #seekTo(int)}
- *         call returns right way, the actual seek operation may take a while to
+ *         <li>Although the asynchronuous {@link #seekTo(int, int)}
+ *         call returns right away, the actual seek operation may take a while to
  *         finish, especially for audio/video being streamed. When the actual
  *         seek operation completes, the internal player engine calls a user
  *         supplied OnSeekComplete.onSeekComplete() if an OnSeekCompleteListener
  *         has been registered beforehand via
  *         {@link #setOnSeekCompleteListener(OnSeekCompleteListener)}.</li>
  *         <li>Please
- *         note that {@link #seekTo(int)} can also be called in the other states,
+ *         note that {@link #seekTo(int, int)} can also be called in the other states,
  *         such as <em>Prepared</em>, <em>Paused</em> and <em>PlaybackCompleted
- *         </em> state.</li>
+ *         </em> state. When {@link #seekTo(int, int)} is called in those states,
+ *         one video frame will be displayed if the stream has video and the requested
+ *         position is valid.
+ *         </li>
  *         <li>Furthermore, the actual current playback position
  *         can be retrieved with a call to {@link #getCurrentPosition()}, which
  *         is helpful for applications such as a Music player that need to keep
@@ -407,7 +410,7 @@
  *          Error} </p></td>
  *     <td>This method must be called in idle state as the audio session ID must be known before
  *         calling setDataSource. Calling it does not change the object state. </p></td></tr>
- * <tr><td>setAudioStreamType </p></td>
+ * <tr><td>setAudioStreamType (deprecated)</p></td>
  *     <td>{Idle, Initialized, Stopped, Prepared, Started, Paused,
  *          PlaybackCompleted}</p></td>
  *     <td>{Error}</p></td>
@@ -819,7 +822,7 @@
      * to free the resources. If not released, too many MediaPlayer instances will
      * result in an exception.</p>
      * <p>Note that since {@link #prepare()} is called automatically in this method,
-     * you cannot change the audio stream type (see {@link #setAudioStreamType(int)}), audio
+     * you cannot change the audio
      * session ID (see {@link #setAudioSessionId(int)}) or audio attributes
      * (see {@link #setAudioAttributes(AudioAttributes)} of the new MediaPlayer.</p>
      *
@@ -838,7 +841,7 @@
      * to free the resources. If not released, too many MediaPlayer instances will
      * result in an exception.</p>
      * <p>Note that since {@link #prepare()} is called automatically in this method,
-     * you cannot change the audio stream type (see {@link #setAudioStreamType(int)}), audio
+     * you cannot change the audio
      * session ID (see {@link #setAudioSessionId(int)}) or audio attributes
      * (see {@link #setAudioAttributes(AudioAttributes)} of the new MediaPlayer.</p>
      *
@@ -901,7 +904,7 @@
      * to free the resources. If not released, too many MediaPlayer instances will
      * result in an exception.</p>
      * <p>Note that since {@link #prepare()} is called automatically in this method,
-     * you cannot change the audio stream type (see {@link #setAudioStreamType(int)}), audio
+     * you cannot change the audio
      * session ID (see {@link #setAudioSessionId(int)}) or audio attributes
      * (see {@link #setAudioAttributes(AudioAttributes)} of the new MediaPlayer.</p>
      *
@@ -1502,13 +1505,107 @@
     public native SyncParams getSyncParams();
 
     /**
+     * Seek modes used in method seekTo(int, int) to move media position
+     * to a specified location.
+     *
+     * Do not change these mode values without updating their counterparts
+     * in include/media/IMediaSource.h!
+     */
+    /**
+     * This mode is used with {@link #seekTo(int, int)} to move media position to
+     * a sync (or key) frame associated with a data source that is located
+     * right before or at the given time.
+     *
+     * @see #seekTo(int, int)
+     */
+    public static final int SEEK_PREVIOUS_SYNC    = 0x00;
+    /**
+     * This mode is used with {@link #seekTo(int, int)} to move media position to
+     * a sync (or key) frame associated with a data source that is located
+     * right after or at the given time.
+     *
+     * @see #seekTo(int, int)
+     */
+    public static final int SEEK_NEXT_SYNC        = 0x01;
+    /**
+     * This mode is used with {@link #seekTo(int, int)} to move media position to
+     * a sync (or key) frame associated with a data source that is located
+     * closest to (in time) or at the given time.
+     *
+     * @see #seekTo(int, int)
+     */
+    public static final int SEEK_CLOSEST_SYNC     = 0x02;
+    /**
+     * This mode is used with {@link #seekTo(int, int)} to move media position to
+     * a frame (not necessarily a key frame) associated with a data source that
+     * is located closest to or at the given time.
+     *
+     * @see #seekTo(int, int)
+     */
+    public static final int SEEK_CLOSEST          = 0x03;
+
+    /** @hide */
+    @IntDef(
+        value = {
+            SEEK_PREVIOUS_SYNC,
+            SEEK_NEXT_SYNC,
+            SEEK_CLOSEST_SYNC,
+            SEEK_CLOSEST,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SeekMode {}
+
+    private native final void _seekTo(int msec, int mode);
+
+    /**
+     * Moves the media to specified time position by considering the given mode.
+     * <p>
+     * When seekTo is finished, the user will be notified via OnSeekComplete supplied by the user.
+     * There is at most one active seekTo processed at any time. If there is a to-be-completed
+     * seekTo, new seekTo requests will be queued in such a way that only the last request
+     * is kept. When current seekTo is completed, the queued request will be processed if
+     * that request is different from just-finished seekTo operation, i.e., the requested
+     * position or mode is different.
+     *
+     * @param msec the offset in milliseconds from the start to seek to.
+     * When seeking to the given time position, there is no guarantee that the data source
+     * has a frame located at the position. When this happens, a frame nearby will be rendered.
+     * If msec is negative, time position zero will be used.
+     * If msec is larger than duration, duration will be used.
+     * @param mode the mode indicating where exactly to seek to.
+     * Use {@link #SEEK_PREVIOUS_SYNC} if one wants to seek to a sync frame
+     * that has a timestamp earlier than or the same as msec. Use
+     * {@link #SEEK_NEXT_SYNC} if one wants to seek to a sync frame
+     * that has a timestamp later than or the same as msec. Use
+     * {@link #SEEK_CLOSEST_SYNC} if one wants to seek to a sync frame
+     * that has a timestamp closest to or the same as msec. Use
+     * {@link #SEEK_CLOSEST} if one wants to seek to a frame that may
+     * or may not be a sync frame but is closest to or the same as msec.
+     * {@link #SEEK_CLOSEST} often has larger performance overhead compared
+     * to the other options if there is no sync frame located at msec.
+     * @throws IllegalStateException if the internal player engine has not been
+     * initialized
+     * @throws IllegalArgumentException if the mode is invalid.
+     */
+    public void seekTo(int msec, @SeekMode int mode) throws IllegalStateException {
+        if (mode < SEEK_PREVIOUS_SYNC || mode > SEEK_CLOSEST) {
+            final String msg = "Illegal seek mode: " + mode;
+            throw new IllegalArgumentException(msg);
+        }
+        _seekTo(msec, mode);
+    }
+
+    /**
      * Seeks to specified time position.
+     * Same as {@link #seekTo(int, int)} with {@code mode = SEEK_PREVIOUS_SYNC}.
      *
      * @param msec the offset in milliseconds from the start to seek to
      * @throws IllegalStateException if the internal player engine has not been
      * initialized
      */
-    public native void seekTo(int msec) throws IllegalStateException;
+    public void seekTo(int msec) throws IllegalStateException {
+        seekTo(msec, SEEK_PREVIOUS_SYNC /* mode */);
+    }
 
     /**
      * Get current playback position as a {@link MediaTimestamp}.
@@ -1746,9 +1843,11 @@
      * thereafter.
      *
      * @param streamtype the audio stream type
+     * @deprecated use {@link #setAudioAttributes(AudioAttributes)}
      * @see android.media.AudioManager
      */
     public void setAudioStreamType(int streamtype) {
+        deprecateStreamTypeForPlayback(streamtype, "MediaPlayer", "setAudioStreamType()");
         baseUpdateAudioAttributes(
                 new AudioAttributes.Builder().setInternalLegacyStreamType(streamtype).build());
         _setAudioStreamType(streamtype);
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index 690a553..42f6b83 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -236,4 +236,28 @@
      */
     abstract void playerSetVolume(boolean muting, float leftVolume, float rightVolume);
     abstract int playerSetAuxEffectSendLevel(boolean muting, float level);
+
+    //=====================================================================
+    // Utilities
+
+    /**
+     * Use to generate warning or exception in legacy code paths that allowed passing stream types
+     * to qualify audio playback.
+     * @param streamType the stream type to check
+     * @throws IllegalArgumentException
+     */
+    public static void deprecateStreamTypeForPlayback(int streamType, String className,
+            String opName) throws IllegalArgumentException {
+        // STREAM_ACCESSIBILITY was introduced at the same time the use of stream types
+        // for audio playback was deprecated, so it is not allowed at all to qualify a playback
+        // use case
+        if (streamType == AudioManager.STREAM_ACCESSIBILITY) {
+            throw new IllegalArgumentException("Use of STREAM_ACCESSIBILITY is reserved for "
+                    + "volume control");
+        }
+        Log.e(className, "Use of stream types is deprecated for operations other than " +
+                "volume control.");
+        Log.e(className, "See the documentation of " + opName + " for what to use instead with " +
+                "android.media.AudioAttributes to qualify your playback use case");
+    }
 }
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 7767712..209ec42 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -103,6 +103,7 @@
      */
     @Deprecated
     public void setStreamType(int streamType) {
+        PlayerBase.deprecateStreamTypeForPlayback(streamType, "Ringtone", "setStreamType()");
         setAudioAttributes(new AudioAttributes.Builder()
                 .setInternalLegacyStreamType(streamType)
                 .build());
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 3cb01de..de9f020 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -297,7 +297,7 @@
     }
 
     /**
-     * Infers the playback stream type based on what type of ringtones this
+     * Infers the volume stream type based on what type of ringtones this
      * manager is returning.
      * 
      * @return The stream type.
@@ -616,6 +616,7 @@
         return getRingtone(context, ringtoneUri, -1);
     }
 
+    //FIXME bypass the notion of stream types within the class
     /**
      * Returns a {@link Ringtone} for a given sound URI on the given stream
      * type. Normally, if you change the stream type on the returned
@@ -630,6 +631,7 @@
         try {
             final Ringtone r = new Ringtone(context, true);
             if (streamType >= 0) {
+                //FIXME deprecated call
                 r.setStreamType(streamType);
             }
             r.setUri(ringtoneUri);
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index b429e22..838767c 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -24,6 +24,7 @@
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.res.AssetFileDescriptor;
+import android.media.PlayerBase;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -146,6 +147,7 @@
     public SoundPool(int maxStreams, int streamType, int srcQuality) {
         this(maxStreams,
                 new AudioAttributes.Builder().setInternalLegacyStreamType(streamType).build());
+        PlayerBase.deprecateStreamTypeForPlayback(streamType, "SoundPool", "SoundPool()");
     }
 
     private SoundPool(int maxStreams, AudioAttributes attributes) {
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index c825702..c52ed94 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -577,15 +577,15 @@
 }
 
 static void
-android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, jint msec)
+android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, jint msec, jint mode)
 {
     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
     if (mp == NULL ) {
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
         return;
     }
-    ALOGV("seekTo: %d(msec)", msec);
-    process_media_player_call( env, thiz, mp->seekTo(msec), NULL, NULL );
+    ALOGV("seekTo: %d(msec), mode=%d", msec, mode);
+    process_media_player_call( env, thiz, mp->seekTo(msec, (MediaPlayerSeekMode)mode), NULL, NULL );
 }
 
 static jint
@@ -1056,7 +1056,7 @@
     {"getPlaybackParams", "()Landroid/media/PlaybackParams;", (void *)android_media_MediaPlayer_getPlaybackParams},
     {"setSyncParams",     "(Landroid/media/SyncParams;)V",  (void *)android_media_MediaPlayer_setSyncParams},
     {"getSyncParams",     "()Landroid/media/SyncParams;",   (void *)android_media_MediaPlayer_getSyncParams},
-    {"seekTo",              "(I)V",                             (void *)android_media_MediaPlayer_seekTo},
+    {"_seekTo",             "(II)V",                            (void *)android_media_MediaPlayer_seekTo},
     {"_pause",              "()V",                              (void *)android_media_MediaPlayer_pause},
     {"isPlaying",           "()Z",                              (void *)android_media_MediaPlayer_isPlaying},
     {"getCurrentPosition",  "()I",                              (void *)android_media_MediaPlayer_getCurrentPosition},
diff --git a/opengl/java/android/opengl/EGL14.java b/opengl/java/android/opengl/EGL14.java
index cf09c58..53ec6c8 100644
--- a/opengl/java/android/opengl/EGL14.java
+++ b/opengl/java/android/opengl/EGL14.java
@@ -284,6 +284,7 @@
 
     // C function EGLSurface eglCreatePixmapSurface ( EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list )
 
+    @Deprecated
     public static native EGLSurface eglCreatePixmapSurface(
         EGLDisplay dpy,
         EGLConfig config,
diff --git a/opengl/java/android/opengl/GLES30.java b/opengl/java/android/opengl/GLES30.java
index 74181c5..3b805d2 100644
--- a/opengl/java/android/opengl/GLES30.java
+++ b/opengl/java/android/opengl/GLES30.java
@@ -590,6 +590,10 @@
 
     // C function void glGetBufferPointerv ( GLenum target, GLenum pname, GLvoid** params )
 
+    /**
+     * The {@link java.nio.Buffer} instance returned by this method is guaranteed
+     * to be an instance of {@link java.nio.ByteBuffer}.
+     */
     public static native java.nio.Buffer glGetBufferPointerv(
         int target,
         int pname
@@ -761,6 +765,10 @@
 
     // C function GLvoid * glMapBufferRange ( GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access )
 
+    /**
+     * The {@link java.nio.Buffer} instance returned by this method is guaranteed
+     * to be an instance of {@link java.nio.ByteBuffer}.
+     */
     public static native java.nio.Buffer glMapBufferRange(
         int target,
         int offset,
diff --git a/opengl/java/javax/microedition/khronos/egl/EGL10.java b/opengl/java/javax/microedition/khronos/egl/EGL10.java
index cf58888..612d59c 100644
--- a/opengl/java/javax/microedition/khronos/egl/EGL10.java
+++ b/opengl/java/javax/microedition/khronos/egl/EGL10.java
@@ -98,6 +98,7 @@
     boolean     eglCopyBuffers(EGLDisplay display, EGLSurface surface, Object native_pixmap);
     EGLContext  eglCreateContext(EGLDisplay display, EGLConfig config, EGLContext share_context, int[] attrib_list);
     EGLSurface  eglCreatePbufferSurface(EGLDisplay display, EGLConfig config, int[] attrib_list);
+    @Deprecated
     EGLSurface  eglCreatePixmapSurface(EGLDisplay display, EGLConfig config, Object native_pixmap, int[] attrib_list);
     EGLSurface  eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list);
     boolean     eglDestroyContext(EGLDisplay display, EGLContext context);
diff --git a/packages/PrintRecommendationService/res/values/donottranslate.xml b/packages/PrintRecommendationService/res/values/donottranslate.xml
index e9b97a3..2cce56d8a 100644
--- a/packages/PrintRecommendationService/res/values/donottranslate.xml
+++ b/packages/PrintRecommendationService/res/values/donottranslate.xml
@@ -32,13 +32,6 @@
         <item>Hewlett Packard</item>
     </string-array>
 
-    <!-- Samsung plugin -->
-    <string-array name="known_print_vendor_info_for_samsung" translatable="false">
-        <item>com.sec.app.samsungprintservice</item>
-        <item>Samsung Electronics</item>
-        <item>Samsung</item>
-    </string-array>
-
     <!-- Xerox plugin -->
     <string-array name="known_print_vendor_info_for_xerox" translatable="false">
         <item>com.xerox.printservice</item>
@@ -49,6 +42,8 @@
     <array name="known_print_plugin_vendors" translatable="false">
         <item>@array/known_print_vendor_info_for_mopria</item>
         <item>@array/known_print_vendor_info_for_hp</item>
-        <item>@array/known_print_vendor_info_for_samsung</item>
     </array>
+
+    <!-- Samsung plugin -->
+    <string name="plugin_package_samsung">com.sec.app.samsungprintservice</string>
 </resources>
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
index 3eedefd..d048396 100644
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
@@ -78,7 +78,7 @@
 
         try {
             mPlugins.add(new RemotePrintServicePlugin(new SamsungRecommendationPlugin(this), this,
-                    false));
+                    true));
         } catch (Exception e) {
             Log.e(LOG_TAG, "Could not initiate " + getString(R.string.plugin_vendor_samsung) +
                     " plugin", e);
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java
index a2c0485..d60a25f 100644
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java
@@ -16,30 +16,52 @@
 
 package com.android.printservice.recommendation.plugin.mdnsFilter;
 
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.StringRes;
 import android.content.Context;
-import android.net.nsd.NsdManager;
 import android.net.nsd.NsdServiceInfo;
-import android.util.Log;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
+import android.annotation.NonNull;
+import android.annotation.StringRes;
+
 import com.android.printservice.recommendation.PrintServicePlugin;
-import com.android.printservice.recommendation.util.DiscoveryListenerMultiplexer;
-import com.android.printservice.recommendation.util.NsdResolveQueue;
+import com.android.printservice.recommendation.util.MDNSFilteredDiscovery;
+import com.android.printservice.recommendation.util.MDNSUtils;
 
 import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 /**
  * A plugin listening for mDNS results and only adding the ones that {@link
  * MDNSUtils#isVendorPrinter match} configured list
  */
-public class MDNSFilterPlugin implements PrintServicePlugin, NsdManager.DiscoveryListener {
-    private static final String LOG_TAG = "MDNSFilterPlugin";
+public class MDNSFilterPlugin implements PrintServicePlugin {
 
-    private static final String PRINTER_SERVICE_TYPE = "_ipp._tcp";
+    /** The mDNS service types supported */
+    private static final Set<String> PRINTER_SERVICE_TYPES = new HashSet<String>() {{
+        add("_ipp._tcp");
+    }};
+
+    /**
+     * The printer filter for {@link MDNSFilteredDiscovery} passing only mDNS results
+     * that {@link MDNSUtils#isVendorPrinter match} configured list
+     */
+    private static class VendorNameFilter implements MDNSFilteredDiscovery.PrinterFilter {
+        /** mDNS names handled by the print service this plugin is for */
+        private final @NonNull Set<String> mMDNSNames;
+
+        /**
+         * Filter constructor
+         *
+         * @param vendorNames The vendor names to pass
+         */
+        VendorNameFilter(@NonNull Set<String> vendorNames) {
+            mMDNSNames = new HashSet<>(vendorNames);
+        }
+
+        @Override
+        public boolean matchesCriteria(NsdServiceInfo nsdServiceInfo) {
+            return MDNSUtils.isVendorPrinter(nsdServiceInfo, mMDNSNames);
+        }
+    }
 
     /** Name of the print service this plugin is for */
     private final @StringRes int mName;
@@ -47,26 +69,8 @@
     /** Package name of the print service this plugin is for */
     private final @NonNull CharSequence mPackageName;
 
-    /** mDNS names handled by the print service this plugin is for */
-    private final @NonNull HashSet<String> mMDNSNames;
-
-    /** Printer identifiers of the mPrinters found. */
-    @GuardedBy("mLock")
-    private final @NonNull HashSet<String> mPrinters;
-
-    /** Context of the user of this plugin */
-    private final @NonNull Context mContext;
-
-    /**
-     * Call back to report the number of mPrinters found.
-     *
-     * We assume that {@link #start} and {@link #stop} are never called in parallel, hence it is
-     * safe to not synchronize access to this field.
-     */
-    private @Nullable PrinterDiscoveryCallback mCallback;
-
-    /** Queue used to resolve nsd infos */
-    private final @NonNull NsdResolveQueue mResolveQueue;
+    /** The mDNS filtered discovery */
+    private final MDNSFilteredDiscovery mMDNSFilteredDiscovery;
 
     /**
      * Create new stub that assumes that a print service can be used to print on all mPrinters
@@ -79,16 +83,11 @@
      */
     public MDNSFilterPlugin(@NonNull Context context, @NonNull String name,
             @NonNull CharSequence packageName, @NonNull List<String> mDNSNames) {
-        mContext = Preconditions.checkNotNull(context, "context");
-        mName = mContext.getResources().getIdentifier(Preconditions.checkStringNotEmpty(name,
-                "name"), null, "com.android.printservice.recommendation");
-        mPackageName = Preconditions.checkStringNotEmpty(packageName);
-        mMDNSNames = new HashSet<>(Preconditions
-                .checkCollectionNotEmpty(Preconditions.checkCollectionElementsNotNull(mDNSNames,
-                        "mDNSNames"), "mDNSNames"));
-
-        mResolveQueue = NsdResolveQueue.getInstance();
-        mPrinters = new HashSet<>();
+        mName = context.getResources().getIdentifier(name, null,
+                "com.android.printservice.recommendation");
+        mPackageName = packageName;
+        mMDNSFilteredDiscovery = new MDNSFilteredDiscovery(context, PRINTER_SERVICE_TYPES,
+                new VendorNameFilter(new HashSet<>(mDNSNames)));
     }
 
     @Override
@@ -96,18 +95,9 @@
         return mPackageName;
     }
 
-    /**
-     * @return The NDS manager
-     */
-    private NsdManager getNDSManager() {
-        return (NsdManager) mContext.getSystemService(Context.NSD_SERVICE);
-    }
-
     @Override
     public void start(@NonNull PrinterDiscoveryCallback callback) throws Exception {
-        mCallback = callback;
-
-        DiscoveryListenerMultiplexer.addListener(getNDSManager(), PRINTER_SERVICE_TYPE, this);
+        mMDNSFilteredDiscovery.start(callback);
     }
 
     @Override
@@ -117,82 +107,6 @@
 
     @Override
     public void stop() throws Exception {
-        mCallback.onChanged(0);
-        mCallback = null;
-
-        DiscoveryListenerMultiplexer.removeListener(getNDSManager(), this);
-    }
-
-    @Override
-    public void onStartDiscoveryFailed(String serviceType, int errorCode) {
-        Log.w(LOG_TAG, "Failed to start network discovery for type " + serviceType + ": "
-                + errorCode);
-    }
-
-    @Override
-    public void onStopDiscoveryFailed(String serviceType, int errorCode) {
-        Log.w(LOG_TAG, "Failed to stop network discovery for type " + serviceType + ": "
-                + errorCode);
-    }
-
-    @Override
-    public void onDiscoveryStarted(String serviceType) {
-        // empty
-    }
-
-    @Override
-    public void onDiscoveryStopped(String serviceType) {
-        mPrinters.clear();
-    }
-
-    @Override
-    public void onServiceFound(NsdServiceInfo serviceInfo) {
-        mResolveQueue.resolve(getNDSManager(), serviceInfo,
-                new NsdManager.ResolveListener() {
-            @Override
-            public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
-                Log.w(LOG_TAG, "Service found: could not resolve " + serviceInfo + ": " +
-                        errorCode);
-            }
-
-            @Override
-            public void onServiceResolved(NsdServiceInfo serviceInfo) {
-                if (MDNSUtils.isVendorPrinter(serviceInfo, mMDNSNames)) {
-                    if (mCallback != null) {
-                        boolean added = mPrinters.add(serviceInfo.getHost().getHostAddress());
-
-                        if (added) {
-                            mCallback.onChanged(mPrinters.size());
-                        }
-                    }
-                }
-            }
-        });
-    }
-
-    @Override
-    public void onServiceLost(NsdServiceInfo serviceInfo) {
-        mResolveQueue.resolve(getNDSManager(), serviceInfo,
-                new NsdManager.ResolveListener() {
-            @Override
-            public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
-                Log.w(LOG_TAG, "Service lost: Could not resolve " + serviceInfo + ": "
-                        + errorCode);
-            }
-
-            @Override
-            public void onServiceResolved(NsdServiceInfo serviceInfo) {
-                if (MDNSUtils.isVendorPrinter(serviceInfo, mMDNSNames)) {
-                    if (mCallback != null) {
-                        boolean removed = mPrinters
-                                .remove(serviceInfo.getHost().getHostAddress());
-
-                        if (removed) {
-                            mCallback.onChanged(mPrinters.size());
-                        }
-                    }
-                }
-            }
-        });
+        mMDNSFilteredDiscovery.stop();
     }
 }
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/MDnsUtils.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/MDnsUtils.java
deleted file mode 100644
index 963e09b..0000000
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/MDnsUtils.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.printservice.recommendation.plugin.samsung;
-
-import android.net.nsd.NsdServiceInfo;
-import android.text.TextUtils;
-
-import java.nio.charset.StandardCharsets;
-import java.util.Locale;
-import java.util.Map;
-
-public class MDnsUtils {
-    public static final String ATTRIBUTE__TY = "ty";
-    public static final String ATTRIBUTE__PRODUCT = "product";
-    public static final String ATTRIBUTE__USB_MFG = "usb_MFG";
-    public static final String ATTRIBUTE__MFG = "mfg";
-
-    public static String getString(byte[] value) {
-        if (value != null) return new String(value,StandardCharsets.UTF_8);
-        return null;
-    }
-
-    public static boolean isVendorPrinter(NsdServiceInfo networkDevice, String[] vendorValues) {
-
-        Map<String,byte[]> attributes = networkDevice.getAttributes();
-        String product = getString(attributes.get(ATTRIBUTE__PRODUCT));
-        String ty = getString(attributes.get(ATTRIBUTE__TY));
-        String usbMfg = getString(attributes.get(ATTRIBUTE__USB_MFG));
-        String mfg = getString(attributes.get(ATTRIBUTE__MFG));
-        return containsVendor(product, vendorValues) || containsVendor(ty, vendorValues) || containsVendor(usbMfg, vendorValues) || containsVendor(mfg, vendorValues);
-
-    }
-
-    public static String getVendor(NsdServiceInfo networkDevice) {
-        String vendor;
-
-        Map<String,byte[]> attributes = networkDevice.getAttributes();
-        vendor = getString(attributes.get(ATTRIBUTE__MFG));
-        if (!TextUtils.isEmpty(vendor)) return vendor;
-        vendor = getString(attributes.get(ATTRIBUTE__USB_MFG));
-        if (!TextUtils.isEmpty(vendor)) return vendor;
-
-        return null;
-    }
-
-    private static boolean containsVendor(String container, String[] vendorValues) {
-        if ((container == null) || (vendorValues == null)) return false;
-        for (String value : vendorValues) {
-            if (containsString(container, value)
-                || containsString(container.toLowerCase(Locale.US), value.toLowerCase(Locale.US))
-                || containsString(container.toUpperCase(Locale.US), value.toUpperCase(Locale.US)))
-                return true;
-        }
-        return false;
-    }
-
-    private static boolean containsString(String container, String contained) {
-        return (container != null) && (contained != null) && (container.equalsIgnoreCase(contained) || container.contains(contained + " "));
-    }
-}
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterFilterMopria.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterFilterMopria.java
new file mode 100644
index 0000000..d03bb1d
--- /dev/null
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterFilterMopria.java
@@ -0,0 +1,63 @@
+/*
+ * (c) Copyright 2016 Samsung Electronics
+ * (c) Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.printservice.recommendation.plugin.samsung;
+
+import android.net.nsd.NsdServiceInfo;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.printservice.recommendation.util.MDNSFilteredDiscovery;
+import com.android.printservice.recommendation.util.MDNSUtils;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Printer filter for Mopria printer models supported by the print service plugin
+ */
+class PrinterFilterMopria implements MDNSFilteredDiscovery.PrinterFilter {
+    private static final String TAG = "PrinterFilterMopria";
+
+    static final Set<String> MOPRIA_MDNS_SERVICES = new HashSet<String>() {{
+        add("_ipp._tcp");
+        add("_ipps._tcp");
+    }};
+
+    private static final String PDL__PDF = "application/pdf";
+    private static final String PDL__PCLM = "application/PCLm";
+    private static final String PDL__PWG_RASTER = "image/pwg-raster";
+
+    private static final String PDL_ATTRIBUTE = "pdl";
+
+    @Override
+    public boolean matchesCriteria(NsdServiceInfo nsdServiceInfo) {
+        if (!MDNSUtils.isSupportedServiceType(nsdServiceInfo, MOPRIA_MDNS_SERVICES)) {
+            return false;
+        }
+
+        String pdls = MDNSUtils.getString(nsdServiceInfo.getAttributes().get(PDL_ATTRIBUTE));
+        boolean isMatch = !TextUtils.isEmpty(pdls)
+                && (pdls.contains(PDL__PDF)
+                || pdls.contains(PDL__PCLM)
+                || pdls.contains(PDL__PWG_RASTER));
+
+        if (isMatch) {
+            Log.d(TAG, "Mopria printer found: " + nsdServiceInfo.getServiceName());
+        }
+        return isMatch;
+    }
+}
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterFilterSamsung.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterFilterSamsung.java
new file mode 100644
index 0000000..5b049ef
--- /dev/null
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterFilterSamsung.java
@@ -0,0 +1,117 @@
+/*
+ * (c) Copyright 2016 Samsung Electronics
+ * (c) Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.printservice.recommendation.plugin.samsung;
+
+import android.net.nsd.NsdServiceInfo;
+import android.annotation.NonNull;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.printservice.recommendation.util.MDNSFilteredDiscovery;
+import com.android.printservice.recommendation.util.MDNSUtils;
+
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Printer filter for Samsung printer models supported by the print service plugin
+ */
+class PrinterFilterSamsung implements MDNSFilteredDiscovery.PrinterFilter {
+    private static final String TAG = "PrinterFilterSamsung";
+
+    static final Set<String> SAMSUNG_MDNS_SERVICES = new HashSet<String>() {{
+        add("_pdl-datastream._tcp");
+    }};
+
+    private static final String[] NOT_SUPPORTED_MODELS = new String[]{
+            "SCX-5x15",
+            "SF-555P",
+            "CF-555P",
+            "SCX-4x16",
+            "SCX-4214F",
+            "CLP-500",
+            "CJX-",
+            "MJC-"
+    };
+    private static final String ATTR_USB_MFG = "usb_MFG";
+    private static final String ATTR_MFG = "mfg";
+    private static final String ATTR_USB_MDL = "usb_MDL";
+    private static final String ATTR_MDL = "mdl";
+    private static final String ATTR_PRODUCT = "product";
+    private static final String ATTR_TY = "ty";
+
+    private static Set<String> SAMUNG_VENDOR_SET = new HashSet<String>() {{
+        add("samsung");
+    }};
+
+    @Override
+    public boolean matchesCriteria(NsdServiceInfo nsdServiceInfo) {
+        if (!MDNSUtils.isSupportedServiceType(nsdServiceInfo, SAMSUNG_MDNS_SERVICES)) {
+            return false;
+        }
+
+        if (!MDNSUtils.isVendorPrinter(nsdServiceInfo, SAMUNG_VENDOR_SET)) {
+            return false;
+        }
+
+        String modelName = getSamsungModelName(nsdServiceInfo);
+        if (modelName != null && isSupportedSamsungModel(modelName)) {
+            Log.d(TAG, "Samsung printer found: " + nsdServiceInfo.getServiceName());
+            return true;
+        }
+        return false;
+    }
+
+    private boolean isSupportedSamsungModel(String model) {
+        if (!TextUtils.isEmpty(model)) {
+            String modelToUpper = model.toUpperCase(Locale.US);
+            for (String unSupportedPrinter : NOT_SUPPORTED_MODELS) {
+                if (modelToUpper.contains(unSupportedPrinter)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    private String getSamsungModelName(@NonNull NsdServiceInfo resolvedDevice) {
+        Map<String,byte[]> attributes = resolvedDevice.getAttributes();
+        String usb_mfg = MDNSUtils.getString(attributes.get(ATTR_USB_MFG));
+        if (TextUtils.isEmpty(usb_mfg)) {
+            usb_mfg = MDNSUtils.getString(attributes.get(ATTR_MFG));
+        }
+
+        String usb_mdl = MDNSUtils.getString(attributes.get(ATTR_USB_MDL));
+        if (TextUtils.isEmpty(usb_mdl)) {
+            usb_mdl = MDNSUtils.getString(attributes.get(ATTR_MDL));
+        }
+
+        String modelName;
+        if (!TextUtils.isEmpty(usb_mfg) && !TextUtils.isEmpty(usb_mdl)) {
+            modelName = usb_mfg.trim() + " " + usb_mdl.trim();
+        } else {
+            modelName = MDNSUtils.getString(attributes.get(ATTR_PRODUCT));
+            if (TextUtils.isEmpty(modelName)) {
+                modelName = MDNSUtils.getString(attributes.get(ATTR_TY));
+            }
+        }
+
+        return modelName;
+    }
+}
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterHashMap.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterHashMap.java
deleted file mode 100644
index 032fe22..0000000
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterHashMap.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.printservice.recommendation.plugin.samsung;
-
-import android.net.nsd.NsdServiceInfo;
-
-import java.util.HashMap;
-
-final class PrinterHashMap extends HashMap<String, NsdServiceInfo> {
-    public static String getKey(NsdServiceInfo serviceInfo) {
-        return serviceInfo.getServiceName();
-    }
-    public NsdServiceInfo addPrinter(NsdServiceInfo device) {
-        return put(getKey(device), device);
-    }
-    public NsdServiceInfo removePrinter(NsdServiceInfo device) {
-        return remove(getKey(device));
-    }
-}
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/SamsungRecommendationPlugin.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/SamsungRecommendationPlugin.java
index e5b8a0f..eeb5122 100644
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/SamsungRecommendationPlugin.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/SamsungRecommendationPlugin.java
@@ -1,102 +1,69 @@
-/*

-(c) Copyright 2016 Samsung Electronics..

-

-Licensed under the Apache License, Version 2.0 (the "License");

-you may not use this file except in compliance with the License.

-You may obtain a copy of the License at

-

-http://www.apache.org/licenses/LICENSE-2.0

-

-Unless required by applicable law or agreed to in writing, software

-distributed under the License is distributed on an "AS IS" BASIS,

-WITHOUT 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.printservice.recommendation.plugin.samsung;

-

-import android.content.Context;

-import android.net.nsd.NsdServiceInfo;

-import android.text.TextUtils;

-

-import java.util.Locale;

-import java.util.Map;

-

-import com.android.printservice.recommendation.R;

-

-public class SamsungRecommendationPlugin extends ServiceRecommendationPlugin {

-

-    private static final String TAG = "SamsungRecommendation";

-

-    private static final String ATTR_USB_MFG = "usb_MFG";

-    private static final String ATTR_MFG = "mfg";

-    private static final String ATTR_USB_MDL = "usb_MDL";

-    private static final String ATTR_MDL = "mdl";

-    private static final String ATTR_PRODUCT = "product";

-    private static final String ATTR_TY = "ty";

-

-    private static String[] mNotSupportedDevices = new String[]{

-            "SCX-5x15",

-            "SF-555P",

-            "CF-555P",

-            "SCX-4x16",

-            "SCX-4214F",

-            "CLP-500",

-            "CJX-",

-            "MJC-"

-    };

-

-    private static boolean isSupportedModel(String model) {

-        if (!TextUtils.isEmpty(model)) {

-            String modelToUpper = model.toUpperCase(Locale.US);

-            for (String unSupportedPrinter : mNotSupportedDevices) {

-                if (modelToUpper.contains(unSupportedPrinter)) {

-                    return  false;

-                }

-            }

-        }

-        return true;

-    }

-

-    public SamsungRecommendationPlugin(Context context) {

-        super(context, R.string.plugin_vendor_samsung, new VendorInfo(context.getResources(), R.array.known_print_vendor_info_for_samsung), new String[]{"_pdl-datastream._tcp"});

-    }

-

-    @Override

-    public boolean matchesCriteria(String vendor, NsdServiceInfo nsdServiceInfo) {

-        if (!TextUtils.equals(vendor, mVendorInfo.mVendorID)) return false;

-

-        String modelName = getModelName(nsdServiceInfo);

-        if (modelName != null) {

-            return (isSupportedModel(modelName));

-        }

-        return false;

-    }

-

-    private String getModelName(NsdServiceInfo resolvedDevice) {

-        Map<String,byte[]> attributes = resolvedDevice.getAttributes();

-        String usb_mfg = MDnsUtils.getString(attributes.get(ATTR_USB_MFG));

-        if (TextUtils.isEmpty(usb_mfg)) {

-            usb_mfg = MDnsUtils.getString(attributes.get(ATTR_MFG));

-        }

-

-        String usb_mdl = MDnsUtils.getString(attributes.get(ATTR_USB_MDL));

-        if (TextUtils.isEmpty(usb_mdl)) {

-            usb_mdl = MDnsUtils.getString(attributes.get(ATTR_MDL));

-        }

-

-        String modelName = null;

-        if (!TextUtils.isEmpty(usb_mfg) && !TextUtils.isEmpty(usb_mdl)) {

-            modelName = usb_mfg.trim() + " " + usb_mdl.trim();

-        } else {

-            modelName = MDnsUtils.getString(attributes.get(ATTR_PRODUCT));

-            if (TextUtils.isEmpty(modelName)) {

-                modelName = MDnsUtils.getString(attributes.get(ATTR_TY));

-            }

-        }

-

-        return modelName;

-    }

-}

+/*
+ * (c) Copyright 2016 Samsung Electronics
+ * (c) Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.printservice.recommendation.plugin.samsung;
+
+import android.content.Context;
+import android.net.nsd.NsdServiceInfo;
+import android.annotation.NonNull;
+
+import com.android.printservice.recommendation.PrintServicePlugin;
+import com.android.printservice.recommendation.R;
+import com.android.printservice.recommendation.util.MDNSFilteredDiscovery;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class SamsungRecommendationPlugin implements PrintServicePlugin {
+    private static final Set<String> ALL_MDNS_SERVICES = new HashSet<String>() {{
+        addAll(PrinterFilterMopria.MOPRIA_MDNS_SERVICES);
+        addAll(PrinterFilterSamsung.SAMSUNG_MDNS_SERVICES);
+    }};
+
+    private final @NonNull Context mContext;
+    private final @NonNull MDNSFilteredDiscovery mMDNSFilteredDiscovery;
+
+    private final @NonNull PrinterFilterSamsung mPrinterFilterSamsung = new PrinterFilterSamsung();
+    private final @NonNull PrinterFilterMopria mPrinterFilterMopria = new PrinterFilterMopria();
+
+    public SamsungRecommendationPlugin(@NonNull Context context) {
+        mContext = context;
+        mMDNSFilteredDiscovery = new MDNSFilteredDiscovery(context, ALL_MDNS_SERVICES,
+                (NsdServiceInfo nsdServiceInfo) ->
+                        mPrinterFilterSamsung.matchesCriteria(nsdServiceInfo) ||
+                                mPrinterFilterMopria.matchesCriteria(nsdServiceInfo));
+    }
+
+    @Override
+    public int getName() {
+        return R.string.plugin_vendor_samsung;
+    }
+
+    @Override
+    public @NonNull CharSequence getPackageName() {
+        return mContext.getString(R.string.plugin_package_samsung);
+    }
+
+    @Override
+    public void start(@NonNull PrinterDiscoveryCallback callback) throws Exception {
+        mMDNSFilteredDiscovery.start(callback);
+    }
+
+    @Override
+    public void stop() throws Exception {
+        mMDNSFilteredDiscovery.stop();
+    }
+}
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/ServiceListener.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/ServiceListener.java
deleted file mode 100644
index 7bb83c9..0000000
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/ServiceListener.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.printservice.recommendation.plugin.samsung;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.net.nsd.NsdManager;
-import android.net.nsd.NsdServiceInfo;
-import android.text.TextUtils;
-import android.util.Pair;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import com.android.printservice.recommendation.R;
-import com.android.printservice.recommendation.util.DiscoveryListenerMultiplexer;
-
-public class ServiceListener implements ServiceResolveQueue.ResolveCallback {
-
-    private final NsdManager mNSDManager;
-    private final Map<String, VendorInfo> mVendorInfoHashMap;
-    private final String[] mServiceType;
-    private final Observer mObserver;
-    private final ServiceResolveQueue mResolveQueue;
-    private List<NsdManager.DiscoveryListener> mListeners = new ArrayList<>();
-    public HashMap<String, PrinterHashMap> mVendorHashMap = new HashMap<>();
-
-    public interface Observer {
-        boolean matchesCriteria(String vendor, NsdServiceInfo serviceInfo);
-        void dataSetChanged();
-    }
-
-    public ServiceListener(Context context, Observer observer, String[] serviceTypes) {
-        mObserver = observer;
-        mServiceType = serviceTypes;
-        mNSDManager = (NsdManager)context.getSystemService(Context.NSD_SERVICE);
-        mResolveQueue = ServiceResolveQueue.getInstance(mNSDManager);
-
-        Map<String, VendorInfo> vendorInfoMap = new HashMap<>();
-        TypedArray testArray = context.getResources().obtainTypedArray(R.array.known_print_plugin_vendors);
-        for(int i = 0; i < testArray.length(); i++) {
-            int arrayID = testArray.getResourceId(i, 0);
-            if (arrayID != 0) {
-                VendorInfo info = new VendorInfo(context.getResources(), arrayID);
-                vendorInfoMap.put(info.mVendorID, info);
-                vendorInfoMap.put(info.mPackageName, info);
-            }
-        }
-        testArray.recycle();
-        mVendorInfoHashMap = vendorInfoMap;
-    }
-
-    @Override
-    public void serviceResolved(NsdServiceInfo nsdServiceInfo) {
-        printerFound(nsdServiceInfo);
-    }
-
-    private synchronized void printerFound(NsdServiceInfo nsdServiceInfo) {
-        if (nsdServiceInfo == null) return;
-        if (TextUtils.isEmpty(PrinterHashMap.getKey(nsdServiceInfo))) return;
-        String vendor = MDnsUtils.getVendor(nsdServiceInfo);
-        if (vendor == null) vendor = "";
-        for(Map.Entry<String,VendorInfo> entry : mVendorInfoHashMap.entrySet()) {
-            for(String vendorValues : entry.getValue().mDNSValues) {
-                if (vendor.equalsIgnoreCase(vendorValues)) {
-                    vendor = entry.getValue().mVendorID;
-                    break;
-                }
-            }
-            // intentional pointer check
-            //noinspection StringEquality
-            if ((vendor != entry.getValue().mVendorID) &&
-                    MDnsUtils.isVendorPrinter(nsdServiceInfo, entry.getValue().mDNSValues)) {
-                vendor = entry.getValue().mVendorID;
-            }
-            // intentional pointer check
-            //noinspection StringEquality
-            if (vendor == entry.getValue().mVendorID) break;
-        }
-
-        if (TextUtils.isEmpty(vendor)) {
-            return;
-        }
-
-        if (!mObserver.matchesCriteria(vendor, nsdServiceInfo))
-            return;
-        boolean mapsChanged;
-
-        PrinterHashMap vendorHash = mVendorHashMap.get(vendor);
-        if (vendorHash == null) {
-            vendorHash = new PrinterHashMap();
-        }
-        mapsChanged = (vendorHash.addPrinter(nsdServiceInfo) == null);
-        mVendorHashMap.put(vendor, vendorHash);
-
-        if (mapsChanged) {
-            mObserver.dataSetChanged();
-        }
-    }
-
-    private synchronized void printerRemoved(NsdServiceInfo nsdServiceInfo) {
-        boolean wasRemoved = false;
-        Set<String> vendors = mVendorHashMap.keySet();
-        for(String vendor : vendors) {
-            PrinterHashMap map = mVendorHashMap.get(vendor);
-            wasRemoved |= (map.removePrinter(nsdServiceInfo) != null);
-            if (map.isEmpty()) wasRemoved |= (mVendorHashMap.remove(vendor) != null);
-        }
-        if (wasRemoved) {
-            mObserver.dataSetChanged();
-        }
-    }
-
-    public void start() {
-        stop();
-        for(final String service :mServiceType) {
-            NsdManager.DiscoveryListener listener = new NsdManager.DiscoveryListener() {
-                @Override
-                public void onStartDiscoveryFailed(String s, int i) {
-
-                }
-
-                @Override
-                public void onStopDiscoveryFailed(String s, int i) {
-
-                }
-
-                @Override
-                public void onDiscoveryStarted(String s) {
-
-                }
-
-                @Override
-                public void onDiscoveryStopped(String s) {
-
-                }
-
-                @Override
-                public void onServiceFound(NsdServiceInfo nsdServiceInfo) {
-                    mResolveQueue.queueRequest(nsdServiceInfo, ServiceListener.this);
-                }
-
-                @Override
-                public void onServiceLost(NsdServiceInfo nsdServiceInfo) {
-                    mResolveQueue.removeRequest(nsdServiceInfo, ServiceListener.this);
-                    printerRemoved(nsdServiceInfo);
-                }
-            };
-            DiscoveryListenerMultiplexer.addListener(mNSDManager, service, listener);
-            mListeners.add(listener);
-        }
-    }
-
-    public void stop() {
-        for(NsdManager.DiscoveryListener listener : mListeners) {
-            DiscoveryListenerMultiplexer.removeListener(mNSDManager, listener);
-        }
-        mVendorHashMap.clear();
-        mListeners.clear();
-    }
-
-    public Pair<Integer, Integer> getCount() {
-        int count = 0;
-        for (PrinterHashMap map : mVendorHashMap.values()) {
-            count += map.size();
-        }
-        return Pair.create(mVendorHashMap.size(), count);
-    }
-}
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/ServiceRecommendationPlugin.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/ServiceRecommendationPlugin.java
deleted file mode 100644
index 9d15f30..0000000
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/ServiceRecommendationPlugin.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.printservice.recommendation.plugin.samsung;
-
-import android.content.Context;
-import android.net.nsd.NsdManager;
-import android.net.nsd.NsdServiceInfo;
-import android.annotation.NonNull;
-import android.text.TextUtils;
-import com.android.printservice.recommendation.PrintServicePlugin;
-
-public abstract class ServiceRecommendationPlugin implements PrintServicePlugin, ServiceListener.Observer {
-
-    protected static final String PDL_ATTRIBUTE = "pdl";
-
-    protected final Object mLock = new Object();
-    protected PrinterDiscoveryCallback mCallback = null;
-    protected final ServiceListener mListener;
-    protected final NsdManager mNSDManager;
-    protected final VendorInfo mVendorInfo;
-    private final int mVendorStringID;
-
-    protected ServiceRecommendationPlugin(Context context, int vendorStringID, VendorInfo vendorInfo, String[] services) {
-        mNSDManager = (NsdManager)context.getSystemService(Context.NSD_SERVICE);
-        mVendorStringID = vendorStringID;
-        mVendorInfo = vendorInfo;
-        mListener = new ServiceListener(context, this, services);
-    }
-
-    @Override
-    public int getName() {
-        return mVendorStringID;
-    }
-
-    @NonNull
-    @Override
-    public CharSequence getPackageName() {
-        return mVendorInfo.mPackageName;
-    }
-
-    @Override
-    public void start(@NonNull PrinterDiscoveryCallback callback) throws Exception {
-        synchronized (mLock) {
-            mCallback = callback;
-        }
-        mListener.start();
-    }
-
-    @Override
-    public void stop() throws Exception {
-        synchronized (mLock) {
-            mCallback = null;
-        }
-        mListener.stop();
-    }
-
-    @Override
-    public void dataSetChanged() {
-        synchronized (mLock) {
-            if (mCallback != null) mCallback.onChanged(getCount());
-        }
-    }
-
-    @Override
-    public boolean matchesCriteria(String vendor, NsdServiceInfo nsdServiceInfo) {
-        return TextUtils.equals(vendor, mVendorInfo.mVendorID);
-    }
-
-    public int getCount() {
-        return mListener.getCount().second;
-    }
-}
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/ServiceResolveQueue.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/ServiceResolveQueue.java
deleted file mode 100644
index e5691b7..0000000
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/ServiceResolveQueue.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.printservice.recommendation.plugin.samsung;
-
-import android.net.nsd.NsdManager;
-import android.net.nsd.NsdServiceInfo;
-import android.util.Pair;
-import com.android.printservice.recommendation.util.NsdResolveQueue;
-
-import java.util.LinkedList;
-
-final class ServiceResolveQueue {
-
-    private final NsdManager mNsdManager;
-    private final LinkedList<Pair<NsdServiceInfo, ResolveCallback>> mQueue = new LinkedList<>();
-    private final Object mLock = new Object();
-
-    private static Object sLock = new Object();
-    private static ServiceResolveQueue sInstance = null;
-    private final NsdResolveQueue mNsdResolveQueue;
-    private Pair<NsdServiceInfo, ResolveCallback> mCurrentRequest = null;
-
-    public static void createInstance(NsdManager nsdManager) {
-        if (sInstance == null) sInstance = new ServiceResolveQueue(nsdManager);
-    }
-
-    public static ServiceResolveQueue getInstance(NsdManager nsdManager) {
-        synchronized (sLock) {
-            createInstance(nsdManager);
-            return sInstance;
-        }
-    }
-
-    public static void destroyInstance() {
-        sInstance = null;
-    }
-
-    public interface ResolveCallback {
-        void serviceResolved(NsdServiceInfo nsdServiceInfo);
-    }
-
-    public ServiceResolveQueue(NsdManager nsdManager) {
-        mNsdManager = nsdManager;
-        mNsdResolveQueue = NsdResolveQueue.getInstance();
-    }
-
-    public void queueRequest(NsdServiceInfo serviceInfo, ResolveCallback callback) {
-        synchronized (mLock) {
-            Pair<NsdServiceInfo, ResolveCallback> newRequest = Pair.create(serviceInfo, callback);
-            if (mQueue.contains(newRequest)) return;
-            mQueue.add(newRequest);
-            makeNextRequest();
-        }
-    }
-
-    public void removeRequest(NsdServiceInfo serviceInfo, ResolveCallback callback) {
-        synchronized (mLock) {
-            Pair<NsdServiceInfo, ResolveCallback> newRequest = Pair.create(serviceInfo, callback);
-            mQueue.remove(newRequest);
-            if ((mCurrentRequest != null) && newRequest.equals(mCurrentRequest)) mCurrentRequest = null;
-        }
-    }
-
-    private void makeNextRequest() {
-        synchronized (mLock) {
-            if (mCurrentRequest != null) return;
-            if (mQueue.isEmpty()) return;
-            mCurrentRequest = mQueue.removeFirst();
-            mNsdResolveQueue.resolve(mNsdManager, mCurrentRequest.first,
-                    new NsdManager.ResolveListener() {
-                        @Override
-                        public void onResolveFailed(NsdServiceInfo nsdServiceInfo, int i) {
-                            synchronized (mLock) {
-                                if (mCurrentRequest != null) mQueue.add(mCurrentRequest);
-                                makeNextRequest();
-                            }
-                        }
-
-                        @Override
-                        public void onServiceResolved(NsdServiceInfo nsdServiceInfo) {
-                            synchronized (mLock) {
-                                if (mCurrentRequest != null) {
-                                    mCurrentRequest.second.serviceResolved(nsdServiceInfo);
-                                    mCurrentRequest = null;
-                                }
-                                makeNextRequest();
-                            }
-                        }
-                    });
-
-        }
-    }
-
-
-}
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/VendorInfo.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/VendorInfo.java
deleted file mode 100644
index 0ebb4e4..0000000
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/VendorInfo.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.printservice.recommendation.plugin.samsung;
-
-import android.content.res.Resources;
-
-import java.util.Arrays;
-
-public final class VendorInfo {
-
-    public final String mPackageName;
-    public final String mVendorID;
-    public final String[] mDNSValues;
-    public final int mID;
-
-    public VendorInfo(Resources resources, int vendor_info_id) {
-        mID = vendor_info_id;
-        String[] data = resources.getStringArray(vendor_info_id);
-        if ((data == null) || (data.length < 2)) {
-            data = new String[] { null, null };
-        }
-        mPackageName = data[0];
-        mVendorID = data[1];
-        mDNSValues = (data.length > 2) ? Arrays.copyOfRange(data, 2, data.length) : new String[]{};
-    }
-}
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/MDNSFilteredDiscovery.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/MDNSFilteredDiscovery.java
new file mode 100644
index 0000000..c5dbc8c
--- /dev/null
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/MDNSFilteredDiscovery.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.printservice.recommendation.util;
+
+import android.content.Context;
+import android.net.nsd.NsdManager;
+import android.net.nsd.NsdServiceInfo;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+import com.android.printservice.recommendation.PrintServicePlugin;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A discovery listening for mDNS results and only adding the ones that {@link
+ * PrinterFilter#matchesCriteria match} configured list
+ */
+public class MDNSFilteredDiscovery implements NsdManager.DiscoveryListener  {
+    private static final String LOG_TAG = "MDNSFilteredDiscovery";
+
+    /**
+     * mDNS service filter interface.
+     * Implement {@link PrinterFilter#matchesCriteria} to filter out supported services
+     */
+    public interface PrinterFilter {
+        /**
+         * Main filter method. Should return true if mDNS service is supported
+         * by the print service plugin
+         *
+         * @param nsdServiceInfo The service info to check
+         *
+         * @return True if service is supported by the print service plugin
+         */
+        boolean matchesCriteria(NsdServiceInfo nsdServiceInfo);
+    }
+
+    /** Printer identifiers of the mPrinters found. */
+    @GuardedBy("mLock")
+    private final @NonNull HashSet<String> mPrinters;
+
+    /** Service types discovered by this plugin */
+    private final @NonNull HashSet<String> mServiceTypes;
+
+    /** Context of the user of this plugin */
+    private final @NonNull Context mContext;
+
+    /** mDNS services filter */
+    private final @NonNull PrinterFilter mPrinterFilter;
+
+    /**
+     * Call back to report the number of mPrinters found.
+     *
+     * We assume that {@link #start} and {@link #stop} are never called in parallel, hence it is
+     * safe to not synchronize access to this field.
+     */
+    private @Nullable PrintServicePlugin.PrinterDiscoveryCallback mCallback;
+
+    /** Queue used to resolve nsd infos */
+    private final @NonNull NsdResolveQueue mResolveQueue;
+
+    /**
+     * Create new stub that assumes that a print service can be used to print on all mPrinters
+     * matching some mDNS names.
+     *
+     * @param context       The context the plugin runs in
+     * @param serviceTypes  The mDNS service types to listen to.
+     * @param printerFilter The filter for mDNS services
+     */
+    public MDNSFilteredDiscovery(@NonNull Context context,
+            @NonNull Set<String> serviceTypes,
+            @NonNull PrinterFilter printerFilter) {
+        mContext = Preconditions.checkNotNull(context, "context");
+        mServiceTypes = new HashSet<>(Preconditions
+                .checkCollectionNotEmpty(Preconditions.checkCollectionElementsNotNull(serviceTypes,
+                        "serviceTypes"), "serviceTypes"));
+        mPrinterFilter = Preconditions.checkNotNull(printerFilter, "printerFilter");
+
+        mResolveQueue = NsdResolveQueue.getInstance();
+        mPrinters = new HashSet<>();
+    }
+
+    /**
+     * @return The NDS manager
+     */
+    private NsdManager getNDSManager() {
+        return (NsdManager) mContext.getSystemService(Context.NSD_SERVICE);
+    }
+
+    /**
+     * Start the discovery.
+     *
+     * @param callback Callbacks used by this plugin.
+     */
+    public void start(@NonNull PrintServicePlugin.PrinterDiscoveryCallback callback) {
+        mCallback = callback;
+        mCallback.onChanged(mPrinters.size());
+
+        for (String serviceType : mServiceTypes) {
+            DiscoveryListenerMultiplexer.addListener(getNDSManager(), serviceType, this);
+        }
+    }
+
+    /**
+     * Stop the discovery. This can only return once the plugin is completely finished and cleaned up.
+     */
+    public void stop() {
+        mCallback.onChanged(0);
+        mCallback = null;
+
+        for (int i = 0; i < mServiceTypes.size(); ++i) {
+            DiscoveryListenerMultiplexer.removeListener(getNDSManager(), this);
+        }
+    }
+
+    /**
+     *
+     * @return The number of discovered printers
+     */
+    public int getCount() {
+        return mPrinters.size();
+    }
+
+    @Override
+    public void onStartDiscoveryFailed(String serviceType, int errorCode) {
+        Log.w(LOG_TAG, "Failed to start network discovery for type " + serviceType + ": "
+                + errorCode);
+    }
+
+    @Override
+    public void onStopDiscoveryFailed(String serviceType, int errorCode) {
+        Log.w(LOG_TAG, "Failed to stop network discovery for type " + serviceType + ": "
+                + errorCode);
+    }
+
+    @Override
+    public void onDiscoveryStarted(String serviceType) {
+        // empty
+    }
+
+    @Override
+    public void onDiscoveryStopped(String serviceType) {
+        mPrinters.clear();
+    }
+
+    @Override
+    public void onServiceFound(NsdServiceInfo serviceInfo) {
+        mResolveQueue.resolve(getNDSManager(), serviceInfo,
+                new NsdManager.ResolveListener() {
+                    @Override
+                    public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
+                        Log.w(LOG_TAG, "Service found: could not resolve " + serviceInfo + ": " +
+                                errorCode);
+                    }
+
+                    @Override
+                    public void onServiceResolved(NsdServiceInfo serviceInfo) {
+                        if (mPrinterFilter.matchesCriteria(serviceInfo)) {
+                            if (mCallback != null) {
+                                boolean added = mPrinters.add(serviceInfo.getHost().getHostAddress());
+                                if (added) {
+                                    mCallback.onChanged(mPrinters.size());
+                                }
+                            }
+                        }
+                    }
+                });
+    }
+
+    @Override
+    public void onServiceLost(NsdServiceInfo serviceInfo) {
+        mResolveQueue.resolve(getNDSManager(), serviceInfo,
+                new NsdManager.ResolveListener() {
+                    @Override
+                    public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
+                        Log.w(LOG_TAG, "Service lost: Could not resolve " + serviceInfo + ": "
+                                + errorCode);
+                    }
+
+                    @Override
+                    public void onServiceResolved(NsdServiceInfo serviceInfo) {
+                        if (mPrinterFilter.matchesCriteria(serviceInfo)) {
+                            if (mCallback != null) {
+                                boolean removed = mPrinters
+                                        .remove(serviceInfo.getHost().getHostAddress());
+
+                                if (removed) {
+                                    mCallback.onChanged(mPrinters.size());
+                                }
+                            }
+                        }
+                    }
+                });
+    }
+}
\ No newline at end of file
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSUtils.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/MDNSUtils.java
similarity index 75%
rename from packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSUtils.java
rename to packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/MDNSUtils.java
index 4c27a47..a6df3c8 100644
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSUtils.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/MDNSUtils.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package com.android.printservice.recommendation.plugin.mdnsFilter;
+package com.android.printservice.recommendation.util;
 
 import android.annotation.NonNull;
 import android.net.nsd.NsdServiceInfo;
@@ -27,12 +27,15 @@
 /**
  * Utils for dealing with mDNS attributes
  */
-class MDNSUtils {
+public class MDNSUtils {
     public static final String ATTRIBUTE_TY = "ty";
     public static final String ATTRIBUTE_PRODUCT = "product";
     public static final String ATTRIBUTE_USB_MFG = "usb_mfg";
     public static final String ATTRIBUTE_MFG = "mfg";
 
+    private MDNSUtils() {
+    }
+
     /**
      * Check if the service has any of a set of vendor names.
      *
@@ -95,4 +98,35 @@
     private static boolean containsString(@NonNull String container, @NonNull String contained) {
         return container.equalsIgnoreCase(contained) || container.contains(contained + " ");
     }
+
+    /**
+     * Return String from mDNS attribute byte array
+     *
+     * @param value the byte array with string data
+     *
+     * @return constructed string
+     */
+    public static String getString(byte[] value) {
+        if (value != null) return new String(value, StandardCharsets.UTF_8);
+        return null;
+    }
+
+    /**
+     * Check if service has a type of supported types set
+     *
+     * @param serviceInfo   The service
+     * @param serviceTypes  The supported service types set
+     *
+     * @return true if service has a type of supported types set
+     */
+    public static boolean isSupportedServiceType(@NonNull NsdServiceInfo serviceInfo,
+            @NonNull Set<String> serviceTypes) {
+        String curType = serviceInfo.getServiceType().toLowerCase();
+        for (String type : serviceTypes) {
+            if (curType.contains(type.toLowerCase())) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/packages/PrintSpooler/res/values-nl/strings.xml b/packages/PrintSpooler/res/values-nl/strings.xml
index a67c84b..21716ca 100644
--- a/packages/PrintSpooler/res/values-nl/strings.xml
+++ b/packages/PrintSpooler/res/values-nl/strings.xml
@@ -97,8 +97,8 @@
     <item msgid="79513688117503758">"Korte zijde"</item>
   </string-array>
   <string-array name="orientation_labels">
-    <item msgid="4061931020926489228">"Portret"</item>
-    <item msgid="3199660090246166812">"Landschap"</item>
+    <item msgid="4061931020926489228">"Staand"</item>
+    <item msgid="3199660090246166812">"Liggend"</item>
   </string-array>
     <string name="print_write_error_message" msgid="5787642615179572543">"Kan niet naar bestand schrijven"</string>
     <string name="print_error_default_message" msgid="8602678405502922346">"Dat werkte niet. Probeer het opnieuw."</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index d0abbf9..a281bba 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ብጁ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"እገዛ እና ግብረመልስ"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"ምናሌ"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"ጂኤምቲ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 0eebcd7..9f6c440 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"مخصص (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"المساعدة والتعليقات"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"القائمة"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"غرينيتش"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index cbb2271..cad5980 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagođeni (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Pomoć i povratne informacije"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Meni"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-be-rBY/strings.xml b/packages/SettingsLib/res/values-be-rBY/strings.xml
index 12f103d..ba5b100 100644
--- a/packages/SettingsLib/res/values-be-rBY/strings.xml
+++ b/packages/SettingsLib/res/values-be-rBY/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Карыстальніцкі (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Даведка і водгукі"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 19382ec..c360f87 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalitzat (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda i suggeriments"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 032d73d..f331080 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Προσαρμοσμένη (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Βοήθεια και σχόλια"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Μενού"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 57738e8..e27822f 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Help &amp; feedback"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 57738e8..e27822f 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Help &amp; feedback"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 57738e8..e27822f 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Help &amp; feedback"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 259e7fb..4353282 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Ayuda y sugerencias"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-eu-rES/strings.xml b/packages/SettingsLib/res/values-eu-rES/strings.xml
index 952fda8..3e08c77 100644
--- a/packages/SettingsLib/res/values-eu-rES/strings.xml
+++ b/packages/SettingsLib/res/values-eu-rES/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Pertsonalizatua (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Laguntza eta iritziak"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Menua"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index bf96b59..648f7b3 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Muokattu (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Ohje ja palaute"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Valikko"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-gu-rIN/strings.xml b/packages/SettingsLib/res/values-gu-rIN/strings.xml
index 1cded3d..a732ea1 100644
--- a/packages/SettingsLib/res/values-gu-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-gu-rIN/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"કસ્ટમ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"સહાય અને પ્રતિસાદ"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"મેનુ"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 07241b5..9559887 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"(<xliff:g id="DENSITYDPI">%d</xliff:g>) khusus"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Bantuan &amp; masukan"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-is-rIS/strings.xml b/packages/SettingsLib/res/values-is-rIS/strings.xml
index 8e8307b..8be8444 100644
--- a/packages/SettingsLib/res/values-is-rIS/strings.xml
+++ b/packages/SettingsLib/res/values-is-rIS/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Sérsniðið (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Hjálp og ábendingar"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Valmynd"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index d894ccf..74ee5a1 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizzato (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Guida e feedback"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ka-rGE/strings.xml b/packages/SettingsLib/res/values-ka-rGE/strings.xml
index 609cb33..8a3b81b 100644
--- a/packages/SettingsLib/res/values-ka-rGE/strings.xml
+++ b/packages/SettingsLib/res/values-ka-rGE/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"მორგებული (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"დახმარება და გამოხმაურება"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"მენიუ"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ky-rKG/strings.xml b/packages/SettingsLib/res/values-ky-rKG/strings.xml
index a2eb86d..3783cce 100644
--- a/packages/SettingsLib/res/values-ky-rKG/strings.xml
+++ b/packages/SettingsLib/res/values-ky-rKG/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Ыңгайлаштырылган (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Жардам жана жооп пикир"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-mk-rMK/strings.xml b/packages/SettingsLib/res/values-mk-rMK/strings.xml
index 711b949..ebe8d00 100644
--- a/packages/SettingsLib/res/values-mk-rMK/strings.xml
+++ b/packages/SettingsLib/res/values-mk-rMK/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Приспособен (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Помош и повратни информации"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Мени"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-mr-rIN/strings.xml b/packages/SettingsLib/res/values-mr-rIN/strings.xml
index 20f64fe..be1fbc6 100644
--- a/packages/SettingsLib/res/values-mr-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-mr-rIN/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"सानुकूल करा (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"मदत आणि अभिप्राय"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"मेनू"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ne-rNP/strings.xml b/packages/SettingsLib/res/values-ne-rNP/strings.xml
index a8a918b..834580b 100644
--- a/packages/SettingsLib/res/values-ne-rNP/strings.xml
+++ b/packages/SettingsLib/res/values-ne-rNP/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"अनुकूलन (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"मद्दत र प्रतिक्रिया"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"मेनु"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 8bb4579..0f2e6d4 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Aangepast (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Help en feedback"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 4db3e6e..738974f 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Niestandardowe (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Pomoc i opinie"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 7855beb..ab866c8 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizada (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e feedback"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 2c366c6..2e4bbdc8 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e comentários"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 7855beb..ab866c8 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizada (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e feedback"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 2cf68a5..5fd58a5 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Прилагођени (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Помоћ и повратне информације"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Мени"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 975a4aa..ee93622 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Anpassad (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Hjälp och feedback"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Meny"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index b538545..29557ec 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Спеціальний масштаб (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Довідка й відгуки"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
index 8d1056a..05879a2 100644
--- a/packages/SettingsLib/res/values-uz-rUZ/strings.xml
+++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Moslashtirilgan (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Yordam va fikr-mulohaza"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Menyu"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index f0ec107..2b1582d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -135,11 +135,11 @@
         mBackgroundHandler = new BackgroundHandler(mThread.getLooper());
 
         // Only the owner can see all apps.
-        mAdminRetrieveFlags = PackageManager.GET_UNINSTALLED_PACKAGES |
-                PackageManager.GET_DISABLED_COMPONENTS |
-                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS;
-        mRetrieveFlags = PackageManager.GET_DISABLED_COMPONENTS |
-                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS;
+        mAdminRetrieveFlags = PackageManager.MATCH_ANY_USER |
+                PackageManager.MATCH_DISABLED_COMPONENTS |
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
+        mRetrieveFlags = PackageManager.MATCH_DISABLED_COMPONENTS |
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
 
         /**
          * This is a trick to prevent the foreground thread from being delayed.
@@ -855,7 +855,7 @@
                         // explicitly include both direct boot aware and unaware components here.
                         List<ResolveInfo> intents = mPm.queryIntentActivitiesAsUser(
                                 launchIntent,
-                                PackageManager.GET_DISABLED_COMPONENTS
+                                PackageManager.MATCH_DISABLED_COMPONENTS
                                         | PackageManager.MATCH_DIRECT_BOOT_AWARE
                                         | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
                                 userId
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
index 5c577f8..e520319 100644
--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
@@ -409,8 +409,8 @@
         // Measure all apps hosted on this volume for all users
         if (mVolume.getType() == VolumeInfo.TYPE_PRIVATE) {
             final List<ApplicationInfo> apps = packageManager.getInstalledApplications(
-                    PackageManager.GET_UNINSTALLED_PACKAGES
-                    | PackageManager.GET_DISABLED_COMPONENTS);
+                    PackageManager.MATCH_ANY_USER
+                    | PackageManager.MATCH_DISABLED_COMPONENTS);
 
             final List<ApplicationInfo> volumeApps = new ArrayList<>();
             for (ApplicationInfo app : apps) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
index c189e1d..c4aa57d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
@@ -112,7 +112,7 @@
             // Enable selected apps
             try {
                 ApplicationInfo info = mIPm.getApplicationInfo(packageName,
-                        PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
+                        PackageManager.MATCH_ANY_USER, userId);
                 if (info == null || !info.enabled
                         || (info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
                     mIPm.installExistingPackageAsUser(packageName, mUser.getIdentifier());
@@ -178,7 +178,7 @@
         addSystemApps(mVisibleApps, widgetIntent, excludePackages);
 
         List<ApplicationInfo> installedApps = pm.getInstalledApplications(
-                PackageManager.MATCH_UNINSTALLED_PACKAGES);
+                PackageManager.MATCH_ANY_USER);
         for (ApplicationInfo app : installedApps) {
             // If it's not installed, skip
             if ((app.flags & ApplicationInfo.FLAG_INSTALLED) == 0) continue;
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index bb85de2..7206127 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -51,6 +51,7 @@
     <bool name="def_wifi_on">false</bool>
     <!-- 0 == never, 1 == only when plugged in, 2 == always -->
     <integer name="def_wifi_sleep_policy">2</integer>
+    <bool name="def_wifi_wakeup_enabled">false</bool>
     <bool name="def_networks_available_notification_on">true</bool>
 
     <bool name="def_backup_enabled">false</bool>
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavBarButtonProvider.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavBarButtonProvider.java
index 09879d8..f653371 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavBarButtonProvider.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavBarButtonProvider.java
@@ -44,7 +44,7 @@
 
         void abortCurrentGesture();
 
-        void setLandscape(boolean landscape);
+        void setVertical(boolean vertical);
 
         void setCarMode(boolean carMode);
     }
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 444f0f0..078f9d7 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -24,17 +24,36 @@
     android:outlineProvider="none"
     android:elevation="5dp" > <!-- Put it above the status bar header -->
 
-    <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
-        android:id="@+id/keyguard_indication_text"
+    <LinearLayout
+        android:id="@+id/keyguard_indication_area"
+        android:forceHasOverlappingRendering="false"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_marginBottom="@dimen/keyguard_indication_margin_bottom"
         android:layout_gravity="bottom|center_horizontal"
-        android:gravity="center_horizontal"
-        android:textStyle="italic"
-        android:textColor="#ffffff"
-        android:textAppearance="?android:attr/textAppearanceSmall"
-        android:accessibilityLiveRegion="polite" />
+        android:orientation="vertical">
+
+        <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
+            android:id="@+id/keyguard_indication_enterprise_disclosure"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_horizontal"
+            android:textStyle="italic"
+            android:textColor="#ffffff"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:visibility="gone" />
+
+        <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
+            android:id="@+id/keyguard_indication_text"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_horizontal"
+            android:textStyle="italic"
+            android:textColor="#ffffff"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:accessibilityLiveRegion="polite" />
+
+    </LinearLayout>
 
     <FrameLayout
         android:id="@+id/preview_container"
diff --git a/packages/SystemUI/res/layout/status_bar_notification_shelf.xml b/packages/SystemUI/res/layout/status_bar_notification_shelf.xml
index 088deba..7bfbd3c 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_shelf.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_shelf.xml
@@ -35,8 +35,8 @@
         android:id="@+id/content"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:paddingStart="13dp"
-        android:paddingEnd="13dp"
+        android:paddingStart="@dimen/shelf_icon_container_padding"
+        android:paddingEnd="@dimen/shelf_icon_container_padding"
         android:gravity="center_vertical" />
 
     <com.android.systemui.statusbar.notification.FakeShadowView
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 5294c9c..40308dc 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Toeganklikheid"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tik om te ontdemp."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tik om op vibreer te stel. Toeganklikheidsdienste kan dalk gedemp wees."</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 601930a..f807ba9 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"ተደራሽነት"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s። ድምጸ-ከል ለማድረግ መታ ያድርጉ"</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s። ወደ ንዝረት ለማቀናበር መታ ያድርጉ። የተደራሽነት አገልግሎቶች ድምጸ-ከል ሊደረግባቸው ይችላል።"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index a1a8f8d..33110ce 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -459,6 +459,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"إمكانية الوصول"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"‏%1$s. انقر لإلغاء التجاهل."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"‏%1$s. انقر للتعيين على الاهتزاز. قد يتم تجاهل خدمات إمكانية الوصول."</string>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index 1bc9e59..49f27b2 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Münasiblik"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Səsli etmək üçün tıklayın."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Vibrasiyanı ayarlamaq üçün tıklayın. Əlçatımlılıq xidmətləri səssiz edilmiş ola bilər."</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 8105d9e..dc21bde 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -453,6 +453,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Pristupačnost"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Dodirnite da biste uključili zvuk."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Dodirnite da biste podesili na vibraciju. Zvuk usluga pristupačnosti će možda biti isključen."</string>
diff --git a/packages/SystemUI/res/values-be-rBY/strings.xml b/packages/SystemUI/res/values-be-rBY/strings.xml
index 83c67d4..ac93da7 100644
--- a/packages/SystemUI/res/values-be-rBY/strings.xml
+++ b/packages/SystemUI/res/values-be-rBY/strings.xml
@@ -457,6 +457,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Спецыяльныя магчымасці"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Дакраніцеся, каб уключыць гук."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Дакраніцеся, каб уключыць вібрацыю. Можа быць адключаны гук службаў спецыяльных магчымасцей."</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index bf3a614..7814efb 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Достъпност"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Докоснете, за да включите отново звука."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Докоснете, за да зададете вибриране. Възможно е звукът на услугите за достъпност да бъде заглушен."</string>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index bd599bc..c80efa4 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -440,18 +440,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> হল ভলিউম ডায়লগ"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"আসলটি পুনঃস্থাপন করতে আলতো চাপ দিন৷"</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"আপনি আপনার কাজের প্রোফাইল ব্যবহার করছেন"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"কল করুন"</item>
-    <item msgid="5997713001067658559">"সিস্টেম"</item>
-    <item msgid="7858983209929864160">"রিং"</item>
-    <item msgid="1850038478268896762">"মিডিয়া"</item>
-    <item msgid="8265110906352372092">"অ্যালার্ম"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"ব্লুটুথ"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s। সশব্দ করতে আলতো চাপুন।"</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s। কম্পন এ সেট করতে আলতো চাপুন। অ্যাক্সেসযোগ্যতার পরিষেবাগুলিকে নিঃশব্দ করা হতে পারে।"</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s। নিঃশব্দ করতে আলতো চাপুন। অ্যাক্সেসযোগ্যতার পরিষেবাগুলিকে নিঃশব্দ করা হতে পারে।"</string>
diff --git a/packages/SystemUI/res/values-bs-rBA/strings.xml b/packages/SystemUI/res/values-bs-rBA/strings.xml
index 5ba720c..2d02a4f 100644
--- a/packages/SystemUI/res/values-bs-rBA/strings.xml
+++ b/packages/SystemUI/res/values-bs-rBA/strings.xml
@@ -453,6 +453,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Pristupačnost"</item>
   </string-array>
     <!-- String.format failed for translation -->
     <!-- no translation found for volume_stream_content_description_unmute (4436631538779230857) -->
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 927e75b..b0e6fe5 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Accessibilitat"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Toca per activar el so."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Toca per activar la vibració. Pot ser que els serveis d\'accessibilitat se silenciïn."</string>
@@ -472,7 +473,7 @@
     <string name="status_bar_airplane" msgid="7057575501472249002">"Mode d\'avió"</string>
     <string name="add_tile" msgid="2995389510240786221">"Afegeix un mosaic"</string>
     <string name="broadcast_tile" msgid="3894036511763289383">"Mosaic d\'emissió"</string>
-    <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"Si no desactives aquesta opció abans, <xliff:g id="WHEN">%1$s</xliff:g> no sentiràs la pròxima alarma"</string>
+    <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"Si no desactives aquesta opció abans, no sentiràs la pròxima alarma (<xliff:g id="WHEN">%1$s</xliff:g>)"</string>
     <string name="zen_alarm_warning" msgid="444533119582244293">"<xliff:g id="WHEN">%1$s</xliff:g> no sentiràs la pròxima alarma"</string>
     <string name="alarm_template" msgid="3980063409350522735">"Hora: <xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="alarm_template_far" msgid="4242179982586714810">"Dia: <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 69629a9..639f8b5 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -457,6 +457,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Přístupnost"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Klepnutím zapnete zvuk."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Klepnutím aktivujete režim vibrací. Služby přístupnosti mohou být ztlumeny."</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 8e34bd0..8fa27ad 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -440,18 +440,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> er dialogboksen for lydstyrke"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"Tryk for at gendanne det oprindelige."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Du bruger din arbejdsprofil"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"Opkald"</item>
-    <item msgid="5997713001067658559">"System"</item>
-    <item msgid="7858983209929864160">"Ring"</item>
-    <item msgid="1850038478268896762">"Medier"</item>
-    <item msgid="8265110906352372092">"Alarm"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"Bluetooth"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tryk for at slå lyden til."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tryk for at konfigurere til at vibrere. Tilgængelighedstjenester kan blive deaktiveret."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Tryk for at slå lyden fra. Lyden i tilgængelighedstjenester kan blive slået fra."</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index b3a457d..564625f 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -442,18 +442,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> regelt die Lautstärke."</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"Tippe, um das Original wiederherzustellen."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Du verwendest dein Arbeitsprofil."</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"Anruf"</item>
-    <item msgid="5997713001067658559">"System"</item>
-    <item msgid="7858983209929864160">"Klingeln lassen"</item>
-    <item msgid="1850038478268896762">"Medien"</item>
-    <item msgid="8265110906352372092">"Wecker"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"Bluetooth"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Zum Aufheben der Stummschaltung tippen."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tippen, um Vibrieren festzulegen. Bedienungshilfen werden unter Umständen stummgeschaltet."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Zum Stummschalten tippen. Bedienungshilfen werden unter Umständen stummgeschaltet."</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 050d7f8..a5c790c 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Προσβασιμότητα"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Πατήστε για κατάργηση σίγασης."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Πατήστε για ενεργοποιήσετε τη δόνηση. Οι υπηρεσίες προσβασιμότητας ενδέχεται να τεθούν σε σίγαση."</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 9aca3cc..5dacfb2 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Accessibility"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tap to unmute."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tap to set to vibrate. Accessibility services may be muted."</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 9aca3cc..5dacfb2 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Accessibility"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tap to unmute."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tap to set to vibrate. Accessibility services may be muted."</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 9aca3cc..5dacfb2 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Accessibility"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tap to unmute."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tap to set to vibrate. Accessibility services may be muted."</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 90c2ca1..3ba4360 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -453,6 +453,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Accesibilidad"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Presiona para dejar de silenciar."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Presiona para establecer el modo vibración. Es posible que los servicios de accesibilidad estén silenciados."</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 0a45ac1..969f812 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -453,6 +453,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Accesibilidad"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Toca para activar el sonido."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Toca para poner el dispositivo en vibración. Los servicios de accesibilidad pueden silenciarse."</string>
@@ -491,8 +492,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"La aplicación no está instalada en tu dispositivo"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Mostrar los segundos del reloj"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Muestra los segundos del reloj en la barra de estado. Puede afectar a la duración de la batería."</string>
-    <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Ajustes rápidos"</string>
-    <string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en Ajustes rápidos"</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar ajustes rápidos"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en ajustes rápidos"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"¿Activar Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para poder conectar tu teclado a tu tablet, debes activar el Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 84fadb2..e1ebfd2 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -442,18 +442,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> on helitugevuse dialoog"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"Puudutage originaali taastamiseks."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Kasutate oma tööprofiili"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"Helistamine"</item>
-    <item msgid="5997713001067658559">"Süsteem"</item>
-    <item msgid="7858983209929864160">"Helin"</item>
-    <item msgid="1850038478268896762">"Meedia"</item>
-    <item msgid="8265110906352372092">"Äratus"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"Bluetooth"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Puudutage vaigistuse tühistamiseks."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Puudutage värinarežiimi määramiseks. Juurdepääsetavuse teenused võidakse vaigistada."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Puudutage vaigistamiseks. Juurdepääsetavuse teenused võidakse vaigistada."</string>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index d6578a2..fa0c711 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -453,6 +453,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Erabilerraztasuna"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Sakatu audioa aktibatzeko."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Sakatu dardara ezartzeko. Baliteke erabilerraztasun-eginbideen audioa desaktibatzea."</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index e00c5b5..bd3c4fc 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -440,18 +440,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> کنترل‌کننده صدا است"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"برای بازیابی نسخه اصلی ضربه بزنید."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"درحال استفاده از نمایه کاری‌تان هستید"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"تماس"</item>
-    <item msgid="5997713001067658559">"سیستم"</item>
-    <item msgid="7858983209929864160">"تماس"</item>
-    <item msgid="1850038478268896762">"رسانه"</item>
-    <item msgid="8265110906352372092">"هشدار"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"بلوتوث"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"‏%1$s. برای باصدا کردن ضربه بزنید."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"‏%1$s. برای تنظیم روی لرزش ضربه بزنید. ممکن است سرویس‌های دسترس‌پذیری بی‌صدا شوند."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"‏%1$s. برای بی‌صدا کردن ضربه بزنید. ممکن است سرویس‌های دسترس‌پذیری بی‌صدا شوند."</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 08572fe..446c9f8 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Esteettömyys"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Poista mykistys koskettamalla."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Siirry värinätilaan koskettamalla. Myös esteettömyyspalvelut saattavat mykistyä."</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 830bfa7..a03e897 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -442,18 +442,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> correspond à la boîte de dialogue du volume"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"Touchez pour restaurer l\'original."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Vous utilisez votre profil professionnel."</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"Appeler"</item>
-    <item msgid="5997713001067658559">"Système"</item>
-    <item msgid="7858983209929864160">"Sonnerie"</item>
-    <item msgid="1850038478268896762">"Multimédia"</item>
-    <item msgid="8265110906352372092">"Alarme"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"Bluetooth"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Touchez pour réactiver le son."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Touchez pour activer les vibrations. Il est possible de couper le son des services d\'accessibilité."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Touchez pour couper le son. Il est possible de couper le son des services d\'accessibilité."</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 3b138c2..1e72795 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -442,18 +442,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> correspond à la boîte de dialogue du volume"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"Appuyez pour rétablir la version d\'origine."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Vous utilisez votre profil professionnel."</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"Appeler"</item>
-    <item msgid="5997713001067658559">"Système"</item>
-    <item msgid="7858983209929864160">"Sonnerie"</item>
-    <item msgid="1850038478268896762">"Multimédia"</item>
-    <item msgid="8265110906352372092">"Alarme"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"Bluetooth"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Appuyez pour ne plus ignorer."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Appuyez pour mettre en mode vibreur. Vous pouvez ignorer les services d\'accessibilité."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Appuyez pour ignorer. Vous pouvez ignorer les services d\'accessibilité."</string>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 579335d..515c729 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -453,6 +453,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Accesibilidade"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Toca para activar o son."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Toca para establecer a vibración. Pódense silenciar os servizos de accesibilidade."</string>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index 48a6d0f..9778b86 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"ઍક્સેસિબિલિટી"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. અનમ્યૂટ કરવા માટે ટૅપ કરો."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. વાઇબ્રેટ પર સેટ કરવા માટે ટૅપ કરો. ઍક્સેસિબિલિટી સેવાઓ મ્યૂટ કરવામાં આવી શકે છે."</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 97f3926..1010126 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -440,18 +440,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> वॉल्यूम संवाद है"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"मूल को पुन: स्थापित करने के लिए टैप करें."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"आप अपनी कार्य प्रोफ़ाइल का उपयोग कर रहे हैं"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"कॉल करें"</item>
-    <item msgid="5997713001067658559">"सिस्‍टम"</item>
-    <item msgid="7858983209929864160">"रिंग करें"</item>
-    <item msgid="1850038478268896762">"मीडिया"</item>
-    <item msgid="8265110906352372092">"अलार्म"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"ब्लूटूथ"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. अनम्यूट करने के लिए टैप करें."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. कंपन पर सेट करने के लिए टैप करें. एक्सेस-योग्यता सेवाएं म्यूट हो सकती हैं."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. म्यूट करने के लिए टैप करें. एक्सेस-योग्यता सेवाएं म्यूट हो सकती हैं."</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 7ff63bd..5d9162e 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -453,6 +453,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Pristupačnost"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Dodirnite da biste uključili zvuk."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Dodirnite da biste postavili na vibraciju. Usluge pristupačnosti možda neće imati zvuk."</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index bd0805b..bb78030 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Kisegítő lehetőségek"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Koppintson a némítás megszüntetéséhez."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Koppintson a rezgés beállításához. Előfordulhat, hogy a kisegítő lehetőségek szolgáltatásai le vannak némítva."</string>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 07966cf..d9ec09e 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -440,18 +440,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ը ձայնի ուժգնության երկխոսության հավելված է"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"Հպեք՝ բնօրինակը վերականգնելու համար:"</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Դուք օգտագործում եք ձեր աշխատանքային պրոֆիլը"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"Զանգել"</item>
-    <item msgid="5997713001067658559">"Համակարգ"</item>
-    <item msgid="7858983209929864160">"Զանգ"</item>
-    <item msgid="1850038478268896762">"Մեդիա"</item>
-    <item msgid="8265110906352372092">"Զարթուցիչ"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"Bluetooth"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s: Հպեք՝ ձայնը միացնելու համար:"</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s: Հպեք՝ թրթռումը միացնելու համար: Մատչելիության ծառայությունների ձայնը կարող է անջատվել:"</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s: Հպեք՝ ձայնն անջատելու համար: Մատչելիության ծառայությունների ձայնը կարող է անջատվել:"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 6444ae5..49d5221 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Aksesibilitas"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Ketuk untuk menyuarakan."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Ketuk untuk menyetel agar bergetar. Layanan aksesibilitas mungkin dibisukan."</string>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index 7e08a01..f95d35f 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Aðgengi"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Ýttu til að hætta að þagga."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Ýttu til að stilla á titring. Hugsanlega verður slökkt á hljóði aðgengisþjónustu."</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 8ffb10d..b30516d 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -453,6 +453,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Accessibilità"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tocca per riattivare l\'audio."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tocca per attivare la vibrazione. L\'audio dei servizi di accessibilità può essere disattivato."</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index a6d7983..c9f907a 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -444,18 +444,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> הוא תיבת הדו-שיח של עוצמת הקול"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"הקש כדי לשחזר את המקור."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"אתה משתמש בפרופיל העבודה שלך"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"שיחה"</item>
-    <item msgid="5997713001067658559">"מערכת"</item>
-    <item msgid="7858983209929864160">"השמע צלצול"</item>
-    <item msgid="1850038478268896762">"מדיה"</item>
-    <item msgid="8265110906352372092">"התראה"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"Bluetooth"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"‏%1$s. הקש כדי לבטל את ההשתקה."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"‏%1$s. הקש כדי להגדיר רטט. ייתכן ששירותי הנגישות מושתקים."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"‏%1$s. הקש כדי להשתיק. ייתכן ששירותי הנגישות מושתקים."</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 6ef9f73..b891b61 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -442,18 +442,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g>を音量ダイアログとして使用"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"タップすると元に戻ります。"</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"仕事用プロファイルを使用しています"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"通話"</item>
-    <item msgid="5997713001067658559">"システム"</item>
-    <item msgid="7858983209929864160">"着信音"</item>
-    <item msgid="1850038478268896762">"メディア"</item>
-    <item msgid="8265110906352372092">"アラーム"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"Bluetooth"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s。タップしてミュートを解除します。"</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s。タップしてバイブレーションに設定します。ユーザー補助機能サービスがミュートされる場合があります。"</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s。タップしてミュートします。ユーザー補助機能サービスがミュートされる場合があります。"</string>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 695279d..e00d6b3 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"მარტივი წვდომა"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. შეეხეთ დადუმების გასაუქმებლად."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. შეეხეთ ვიბრაციაზე დასაყენებლად. შეიძლება დადუმდეს მარტივი წვდომის სერვისებიც."</string>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index ba71182..92b94bd 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -440,18 +440,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> — көлем диалогтық терезесі"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"Бастапқы қалпына келтіру үшін түртіңіз."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Сіз жұмыс профиліңізді пайдаланып жатырсыз"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"Қоңырау шалу"</item>
-    <item msgid="5997713001067658559">"Жүйе"</item>
-    <item msgid="7858983209929864160">"Шылдырлау"</item>
-    <item msgid="1850038478268896762">"Мультимeдиа"</item>
-    <item msgid="8265110906352372092">"Дабыл"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"Bluetooth"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Дыбысын қосу үшін түртіңіз."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Діріл режимін орнату үшін түртіңіз. Арнайы мүмкіндік қызметтерінің дыбысы өшуі мүмкін."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Дыбысын өшіру үшін түртіңіз. Арнайы мүмкіндік қызметтерінің дыбысы өшуі мүмкін."</string>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index b222555..9a352fc 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -440,18 +440,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> គឺជាប្រអប់សម្លេង"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"ប៉ះដើម្បីស្តារច្បាប់ដើម"</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"អ្នកកំពុងប្រើប្រវត្តិរូបការងាររបស់អ្នក"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"ហៅ"</item>
-    <item msgid="5997713001067658559">"ប្រព័ន្ធ"</item>
-    <item msgid="7858983209929864160">"រោទ៍"</item>
-    <item msgid="1850038478268896762">"មេឌៀ"</item>
-    <item msgid="8265110906352372092">"ម៉ោងរោទ៍"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"ប៊្លូធូស"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s។ ប៉ះដើម្បីបើកសំឡេង។"</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s។ ប៉ះដើម្បីកំណត់ឲ្យញ័រ។ សេវាកម្មលទ្ធភាពប្រើប្រាស់អាចនឹងត្រូវបានបិទសំឡេង។"</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s។ ប៉ះដើម្បីបិទសំឡេង។ សេវាកម្មលទ្ធភាពប្រើប្រាស់អាចនឹងត្រូវបានបិទសំឡេង។"</string>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index b2a6f27..990c721 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -440,18 +440,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ವಾಲ್ಯೂಮ್ ಸಂವಾದವಾಗಿದೆ"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"ಮೂಲಕ್ಕೆ ಮರುಸ್ಥಾಪಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್‌ ಅನ್ನು ನೀವು ಬಳಸುತ್ತಿರುವಿರಿ"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"ಕರೆಮಾಡಿ"</item>
-    <item msgid="5997713001067658559">"ಸಿಸ್ಟಂ"</item>
-    <item msgid="7858983209929864160">"ಉಂಗುರ"</item>
-    <item msgid="1850038478268896762">"ಮಾಧ್ಯಮ"</item>
-    <item msgid="8265110906352372092">"ಅಲಾರಮ್"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"ಬ್ಲೂಟೂತ್‌"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. ಅನ್‌ಮ್ಯೂಟ್‌ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. ಕಂಪನಕ್ಕೆ ಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಪ್ರವೇಶಿಸುವಿಕೆ ಸೇವೆಗಳನ್ನು ಮ್ಯೂಟ್‌ ಮಾಡಬಹುದು."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. ಮ್ಯೂಟ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಪ್ರವೇಶಿಸುವಿಕೆ ಸೇವೆಗಳನ್ನು ಮ್ಯೂಟ್‌ ಮಾಡಬಹುದು."</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index cefb57a..b06f15e 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -442,18 +442,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g>은(는) 볼륨 대화입니다."</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"원본을 복원하려면 탭하세요."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"직장 프로필을 사용하고 있습니다."</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"통화"</item>
-    <item msgid="5997713001067658559">"시스템"</item>
-    <item msgid="7858983209929864160">"벨 울리기"</item>
-    <item msgid="1850038478268896762">"미디어"</item>
-    <item msgid="8265110906352372092">"알람"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"블루투스"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. 탭하여 음소거를 해제하세요."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. 탭하여 진동으로 설정하세요. 접근성 서비스가 음소거될 수 있습니다."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. 탭하여 음소거로 설정하세요. 접근성 서비스가 음소거될 수 있습니다."</string>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index e013c6b..d5af0b3 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Атайын мүмкүнчүлүктөр"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Үнүн чыгаруу үчүн таптап коюңуз."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Дирилдөөгө коюу үчүн таптап коюңуз. Атайын мүмкүнчүлүктөр кызматынын үнүн өчүрүп койсо болот."</string>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 94e789a..711a68d 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -440,18 +440,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ແມ່ນ​ໜ້າ​ຕ່າງ​ລະ​ດັບ​ສຽງ"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"ແຕະເພື່ອກູ້ຕົ້ນສະບັບຄືນມາ."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"ທ່ານກຳລັງໃຊ້ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຂອງທ່ານ"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"ໂທ"</item>
-    <item msgid="5997713001067658559">"ລະບົບ"</item>
-    <item msgid="7858983209929864160">"​ເຕືອນ​ດ້ວຍ​ສຽງ"</item>
-    <item msgid="1850038478268896762">"ມີເດຍ"</item>
-    <item msgid="8265110906352372092">"ໂມງປຸກ"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"Bluetooth"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. ແຕະເພື່ອເຊົາປິດສຽງ."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. ແຕະເພື່ອຕັ້ງເປັນສັ່ນ. ບໍລິການຊ່ວຍເຂົ້າເຖິງອາດຖືກປິດສຽງໄວ້."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. ແຕະເພື່ອປິດສຽງ. ບໍລິການຊ່ວຍເຂົ້າເຖິງອາດຖືກປິດສຽງໄວ້."</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 5af5979..aec484d 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -444,18 +444,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ yra garsumo valdymo dialogo langas"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"Palieskite, kad atkurtumėte originalą."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Naudojate darbo profilį"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"Skambinti"</item>
-    <item msgid="5997713001067658559">"Sistema"</item>
-    <item msgid="7858983209929864160">"Skambinti"</item>
-    <item msgid="1850038478268896762">"Medija"</item>
-    <item msgid="8265110906352372092">"Signalas"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"Bluetooth"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Palieskite, kad įjungtumėte garsą."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Palieskite, kad nustatytumėte vibravimą. Gali būti nutildytos pritaikymo neįgaliesiems paslaugos."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Palieskite, kad nutildytumėte. Gali būti nutildytos pritaikymo neįgaliesiems paslaugos."</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 503c8c8..900a955d 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -442,18 +442,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ir skaļuma dialoglodziņš"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"Pieskarieties, lai atjaunotu sākotnējo saturu."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Jūs izmantojat darba profilu."</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"Zvans"</item>
-    <item msgid="5997713001067658559">"Sistēma"</item>
-    <item msgid="7858983209929864160">"Zvanīt"</item>
-    <item msgid="1850038478268896762">"Multivide"</item>
-    <item msgid="8265110906352372092">"Signāls"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"Bluetooth"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Pieskarieties, lai ieslēgtu skaņu."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Pieskarieties, lai iestatītu uz vibrozvanu. Var tikt izslēgti pieejamības pakalpojumu signāli."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Pieskarieties, lai izslēgtu skaņu. Var tikt izslēgti pieejamības pakalpojumu signāli."</string>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 62fc350..716f76c 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Пристапност"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Допрете за да вклучите звук."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Допрете за да поставите на вибрации. Можеби ќе се исклучи звукот на услугите за достапност."</string>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 9e7d2f2..6c14826 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -440,18 +440,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g>, വോളിയം ഡയലോഗാണ്"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"ഒറിജിനൽ പുനഃസ്ഥാപിക്കാൻ ടാപ്പുചെയ്യുക."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"നിങ്ങൾ ഉപയോഗിക്കുന്നത് ഔദ്യോഗിക പ്രൊഫൈലാണ്"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"വിളിക്കുക"</item>
-    <item msgid="5997713001067658559">"സിസ്‌റ്റം"</item>
-    <item msgid="7858983209929864160">"റിംഗുചെയ്യുക"</item>
-    <item msgid="1850038478268896762">"മീഡിയ"</item>
-    <item msgid="8265110906352372092">"അലാറം"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"ബ്ലൂടൂത്ത്"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. അൺമ്യൂട്ടുചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. വൈബ്രേറ്റിലേക്ക് സജ്ജമാക്കുന്നതിന് ടാപ്പുചെയ്യുക. പ്രവേശനക്ഷമതാ സേവനങ്ങൾ മ്യൂട്ടുചെയ്യപ്പെട്ടേക്കാം."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. മ്യൂട്ടുചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക. പ്രവേശനക്ഷമതാ സേവനങ്ങൾ മ്യൂട്ടുചെയ്യപ്പെട്ടേക്കാം."</string>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 04fb4c2..8171310 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -410,12 +410,12 @@
     <string name="monitoring_description_vpn_device_owned" msgid="3090670777499161246">"Таны төхөөрөмжийн удирдагч <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nТаны админ таны төхөөрөмжтэй холбоотой тохиргоо, байгууллагын хандалт, мэдээлэл болон байршлын мэдээллийг удирдан, хяналт тавих боломжтой.\n\nТа таны имэйл, апп, вэб сайтын үйл ажиллагааг хянах VPN-д холбогдсон байна.\n\nДэлгэрэнгүй мэдээлэл авахыг хүсвэл админтайгаа холбогдоно уу."</string>
     <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг.\n\nАдмин нь таны имэйл,апп болон вэбсайт зэрэг сүлжээний үйл ажиллагааг хянадаг. \n\n Дэлгэрэнгүй мэдээлэл авахыг хүсвэл админтайгаа холбогдоно уу. \n\nМөн та VPN-д холбогдсон бөгөөд ингэснээр өөрийн сүлжээний үйл ажиллагааг хянах боломжтой байна."</string>
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
-    <string name="monitoring_description_app" msgid="6259179342284742878">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вебсайт зэрэг сүлжээний үйл ажиллагааг хянах боломжтой."</string>
-    <string name="monitoring_description_app_personal" msgid="484599052118316268">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вебсайт зэрэг сүлжээний хувийн үйл ажиллагааг хянах боломжтой."</string>
+    <string name="monitoring_description_app" msgid="6259179342284742878">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вэбсайт зэрэг сүлжээний үйл ажиллагааг хянах боломжтой."</string>
+    <string name="monitoring_description_app_personal" msgid="484599052118316268">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вэбсайт зэрэг сүлжээний хувийн үйл ажиллагааг хянах боломжтой."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Та имэйл, апп, вэб хуудас зэрэг хувийн сүлжээнийхээ үйл ажиллагааг хянах боломжтой <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон байна."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг. Энэ нь <xliff:g id="APPLICATION">%2$s</xliff:g>-тэй холбогдсон бөгөөд таны  имэйл, апп, вебсайт зэрэг сүлжээний үйл ажиллагааг хянах боломжтой.\n\nДэлгэрэнгүй мэдээлэл авахыг хүсвэл админтайгаа холбогдоно уу."</string>
-    <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг. Энэ нь <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>-тай холбогдсон бөгөөд таны имэйл, апп, вебсайт зэрэг ажлын сүлжээний үйл ажиллагааг хянах боломжтой.\n\nМөн та <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны сүлжээний хувийн үйл ажиллагааг хянаж чадна."</string>
-    <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Таны төхөөрөмжийг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг.\n\n Танай админ төхөөрөмж, төхөөрөмжийн байршилтай холбоотой өгөгдлийг холбох, тохиргоог өөрчлөх болон хяналт тавих боломжтой.\n\nТа <xliff:g id="APPLICATION">%2$s</xliff:g>-тай холбогдсон бөгөөд ингэснээр таны имэйл,апп, аюулгүй вебсайт зэрэг сүлжээний үйл ажиллагаагаа хянах боломжтой.\n\n Дэлгэрэнгүй мэдээлэл авахыг хүсвэл админтайгаа холбогдоно уу."</string>
+    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг. Энэ нь <xliff:g id="APPLICATION">%2$s</xliff:g>-тэй холбогдсон бөгөөд таны  имэйл, апп, вэбсайт зэрэг сүлжээний үйл ажиллагааг хянах боломжтой.\n\nДэлгэрэнгүй мэдээлэл авахыг хүсвэл админтайгаа холбогдоно уу."</string>
+    <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг. Энэ нь <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>-тай холбогдсон бөгөөд таны имэйл, апп, вэбсайт зэрэг ажлын сүлжээний үйл ажиллагааг хянах боломжтой.\n\nМөн та <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны сүлжээний хувийн үйл ажиллагааг хянаж чадна."</string>
+    <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Таны төхөөрөмжийг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг.\n\n Танай админ төхөөрөмж, төхөөрөмжийн байршилтай холбоотой өгөгдлийг холбох, тохиргоог өөрчлөх болон хяналт тавих боломжтой.\n\nТа <xliff:g id="APPLICATION">%2$s</xliff:g>-тай холбогдсон бөгөөд ингэснээр таны имэйл,апп, аюулгүй вэбсайт зэрэг сүлжээний үйл ажиллагаагаа хянах боломжтой.\n\n Дэлгэрэнгүй мэдээлэл авахыг хүсвэл админтайгаа холбогдоно уу."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Таныг гараар онгойлгох хүртэл төхөөрөмж түгжээтэй байх болно"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Мэдэгдлийг хурдан авах"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"Түгжээг тайлахын өмнө үзнэ үү"</string>
@@ -438,18 +438,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь дууны диалог юм."</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"Эх хувилбарыг сэргээхийн тулд дарна уу."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Та өөрийн ажлын профайлыг ашиглаж байна"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"Дуудлага"</item>
-    <item msgid="5997713001067658559">"Систем"</item>
-    <item msgid="7858983209929864160">"Хонх дуугаргах"</item>
-    <item msgid="1850038478268896762">"Медиа"</item>
-    <item msgid="8265110906352372092">"Сэрүүлэг"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"Bluetooth"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Дууг нь нээхийн тулд товшино уу."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Чичиргээнд тохируулахын тулд товшино уу. Хүртээмжийн үйлчилгээний дууг хаасан."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Дууг нь хаахын тулд товшино уу. Хүртээмжийн үйлчилгээний дууг хаасан."</string>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index a21019a..ade3921 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"प्रवेशयोग्यता"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. सशब्द करण्यासाठी टॅप करा."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. कंपन सेट करण्यासाठी टॅप करा. प्रवेशयोग्यता सेवा नि:शब्द केल्या जाऊ शकतात."</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index ce94295..ebe2cf8 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -440,18 +440,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ialah dialog kelantangan"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"Ketik untuk memulihkan yang asal."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Anda sedang menggunakan profil kerja"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"Panggil"</item>
-    <item msgid="5997713001067658559">"Sistem"</item>
-    <item msgid="7858983209929864160">"Dering"</item>
-    <item msgid="1850038478268896762">"Media"</item>
-    <item msgid="8265110906352372092">"Penggera"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"Bluetooth"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Ketik untuk menyahredam."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Ketik untuk menetapkan pada getar. Perkhidmatan kebolehaksesan mungkin diredamkan."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Ketik untuk meredam. Perkhidmatan kebolehaksesan mungkin diredamkan."</string>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 8ab1de0..a1e6d37 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"အများသုံးစွဲနိုင်မှု"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s။ အသံပြန်ဖွင့်ရန် တို့ပါ။"</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s။ တုန်ခါမှုကို သတ်မှတ်ရန် တို့ပါ။ အများသုံးစွဲနိုင်မှု ဝန်ဆောင်မှုများကို အသံပိတ်ထားနိုင်ပါသည်။"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index c6312e1..4508276 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Tilgjengelighet"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Trykk for å slå på lyden."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Trykk for å angi vibrasjon. Lyden kan bli slått av for tilgjengelighetstjenestene."</string>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index f87223c..7afcac1 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"पहुँच"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s। अनम्यूट गर्नका लागि ट्याप गर्नुहोस्।"</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s। कम्पनमा सेट गर्नका लागि ट्याप गर्नुहोस्। पहुँच सम्बन्धी सेवाहरू म्यूट हुन सक्छन्।"</string>
diff --git a/packages/SystemUI/res/values-nl-land/strings.xml b/packages/SystemUI/res/values-nl-land/strings.xml
index d762d07..48624eb 100644
--- a/packages/SystemUI/res/values-nl-land/strings.xml
+++ b/packages/SystemUI/res/values-nl-land/strings.xml
@@ -19,5 +19,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="toast_rotation_locked" msgid="7609673011431556092">"Het scherm is nu vergrendeld in liggende (landschap) stand."</string>
+    <string name="toast_rotation_locked" msgid="7609673011431556092">"Het scherm is nu vergrendeld in liggende stand."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 29f8875..a13030d 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -274,8 +274,8 @@
     <string name="accessibility_quick_settings_rotation" msgid="4231661040698488779">"Scherm automatisch draaien"</string>
     <string name="accessibility_quick_settings_rotation_value" msgid="1428962304214992318">"Instellen op <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotatie vergrendeld"</string>
-    <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Portret"</string>
-    <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Landschap"</string>
+    <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Staand"</string>
+    <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Liggend"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"Invoermethode"</string>
     <string name="quick_settings_location_label" msgid="5011327048748762257">"Locatie"</string>
     <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Locatie uit"</string>
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Toegankelijkheid"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tik om dempen op te heffen."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tik om in te stellen op trillen. Toegankelijkheidsservices kunnen zijn gedempt."</string>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index f25662b..6b5abe4 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -440,18 +440,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਵੋਲਯੂਮ ਡਾਇਲੌਗ ਹੈ"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"ਅਸਲ ਨੂੰ ਮੁੜ-ਬਹਾਲ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"ਤੁਸੀਂ ਆਪਣੀ ਕੰਮ ਪ੍ਰੋਫਾਈਲ ਵਰਤ ਰਹੇ ਹੋ"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"ਕਾਲ ਕਰੋ"</item>
-    <item msgid="5997713001067658559">"ਸਿਸਟਮ"</item>
-    <item msgid="7858983209929864160">"ਰਿੰਗ ਕਰੋ"</item>
-    <item msgid="1850038478268896762">"ਮੀਡੀਆ"</item>
-    <item msgid="8265110906352372092">"ਅਲਾਰਮ"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"ਬਲੂਟੁੱਥ"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s। ਅਣਮਿਊਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s। ਥਰਥਰਾਹਟ ਸੈੱਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ। ਪਹੁੰਚਯੋਗਤਾ ਸੇਵਾਵਾਂ ਮਿਊਟ ਹੋ ਸਕਦੀਆਂ ਹਨ।"</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s। ਮਿਊਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ। ਪਹੁੰਚਯੋਗਤਾ ਸੇਵਾਵਾਂ ਮਿਊਟ ਹੋ ਸਕਦੀਆਂ ਹਨ।"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 78c6102..429fdfb 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -399,7 +399,7 @@
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Wyłącz oszczędzanie baterii"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> będzie zapisywać wszystko, co wyświetli się na ekranie."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Nie pokazuj ponownie"</string>
-    <string name="clear_all_notifications_text" msgid="814192889771462828">"Usuń wszystkie"</string>
+    <string name="clear_all_notifications_text" msgid="814192889771462828">"Ukryj wszystkie"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Rozpocznij teraz"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Brak powiadomień"</string>
     <string name="device_owned_footer" msgid="3802752663326030053">"Urządzenie może być monitorowane"</string>
@@ -455,6 +455,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Ułatwienia dostępu"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Kliknij, by wyłączyć wyciszenie."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Kliknij, by włączyć wibracje. Ułatwienia dostępu mogą być wyciszone."</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 0dbdcb9..828d4d9 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -453,6 +453,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Acessibilidade"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Toque para ativar o som."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Toque para configurar para vibrar. É possível que os serviços de acessibilidade sejam silenciados."</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index d037cda..60a1cda 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Acessibilidade"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Toque para reativar o som."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Toque para ativar a vibração. Os serviços de acessibilidade podem ser silenciados."</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 0dbdcb9..828d4d9 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -453,6 +453,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Acessibilidade"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Toque para ativar o som."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Toque para configurar para vibrar. É possível que os serviços de acessibilidade sejam silenciados."</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index e33ebb5..b418d4a 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -444,18 +444,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> afișează caseta de dialog pentru volum"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"Atingeți pentru a restabili versiunea originală."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Acum folosiți profilul de serviciu"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"Apel"</item>
-    <item msgid="5997713001067658559">"Sistem"</item>
-    <item msgid="7858983209929864160">"Sonerie"</item>
-    <item msgid="1850038478268896762">"Conținut media"</item>
-    <item msgid="8265110906352372092">"Alarmă"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"Bluetooth"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Atingeți pentru a activa sunetul."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Atingeți pentru a seta vibrarea. Sunetul se poate dezactiva pentru serviciile de accesibilitate."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Atingeți pentru a dezactiva sunetul. Sunetul se poate dezactiva pentru serviciile de accesibilitate."</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 0fbb0bd..05f0d38 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -457,6 +457,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Специальные возможности"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Нажмите, чтобы включить звук."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Нажмите, чтобы включить вибрацию. Специальные возможности могут прекратить работу."</string>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index c4d2378..2db54d0 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -187,7 +187,7 @@
     <string name="accessibility_desc_close" msgid="7479755364962766729">"වසන්න"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi අක්‍රියයි."</string>
-    <string name="accessibility_quick_settings_wifi_changed_on" msgid="6440117170789528622">"Wifi සක්‍රියයි."</string>
+    <string name="accessibility_quick_settings_wifi_changed_on" msgid="6440117170789528622">"Wifi ක්‍රියාත්මකයි."</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"ජංගම <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"බැටරිය <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_airplane_off" msgid="7786329360056634412">"අහස්යානා අකාරය අක්‍රියයි."</string>
@@ -203,15 +203,15 @@
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"බාධා නොකරන්න ක්‍රියාත්මක කරන ලදි"</string>
     <string name="accessibility_quick_settings_bluetooth" msgid="6341675755803320038">"බ්ලූටූත්."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"බ්ලූටූත් අක්‍රියයි."</string>
-    <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"බ්ලූටූත් සක්‍රියයි."</string>
+    <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"බ්ලූටූත් ක්‍රියාත්මකයි."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"බ්ලූටූත් සම්බන්ධවෙමින්."</string>
     <string name="accessibility_quick_settings_bluetooth_connected" msgid="4306637793614573659">"බ්ලූටූත් සම්බන්ධිතයි."</string>
     <string name="accessibility_quick_settings_bluetooth_changed_off" msgid="2730003763480934529">"බ්ලූටූත් අක්‍රියයි."</string>
-    <string name="accessibility_quick_settings_bluetooth_changed_on" msgid="8722351798763206577">"බ්ලූටූත් සක්‍රියයි."</string>
+    <string name="accessibility_quick_settings_bluetooth_changed_on" msgid="8722351798763206577">"බ්ලූටූත් ක්‍රියාත්මක කෙරිණි."</string>
     <string name="accessibility_quick_settings_location_off" msgid="5119080556976115520">"ස්ථානය වාර්තාකරණය අක්‍රියයි."</string>
-    <string name="accessibility_quick_settings_location_on" msgid="5809937096590102036">"ස්ථානය වාර්තාකරණය සක්‍රියයි."</string>
+    <string name="accessibility_quick_settings_location_on" msgid="5809937096590102036">"ස්ථානය වාර්තාකරණය ක්‍රියාත්මකයි."</string>
     <string name="accessibility_quick_settings_location_changed_off" msgid="8526845571503387376">"ස්ථානය වාර්තාකරණය අක්‍රියයි."</string>
-    <string name="accessibility_quick_settings_location_changed_on" msgid="339403053079338468">"ස්ථානය වාර්තාකරණය සක්‍රියයි."</string>
+    <string name="accessibility_quick_settings_location_changed_on" msgid="339403053079338468">"ස්ථානය වාර්තාකරණය ක්‍රියාත්මක කෙරිණි."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"<xliff:g id="TIME">%s</xliff:g> සඳහා සීනුව සකස් කර ඇත."</string>
     <string name="accessibility_quick_settings_close" msgid="3115847794692516306">"පැනලය වහන්න."</string>
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"වේලාව වැඩියෙන්."</string>
@@ -232,7 +232,7 @@
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"වැඩ ප්‍රකාරය ක්‍රියාත්මක කරන ලදී."</string>
     <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"දත්ත සුරැකුම ක්‍රියාවිරහිත කරන ලදී."</string>
     <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"දත්ත සුරැකුම ක්‍රියාත්මක කරන ලදී."</string>
-    <string name="accessibility_brightness" msgid="8003681285547803095">"දීප්තිය දර්ශනය කරන්න"</string>
+    <string name="accessibility_brightness" msgid="8003681285547803095">"සංදර්ශක දීප්තිය"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G දත්ත විරාම කර ඇත"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G දත්ත විරාම කර ඇත"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"සෙලියුලර් දත්ත විරාම කර ඇත"</string>
@@ -263,7 +263,7 @@
     <string name="ethernet_label" msgid="7967563676324087464">"ඊතර නෙට්"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"බාධා නොකරන්න"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"ප්‍රමුඛතාව පමණයි"</string>
-    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"ඇඟවීම් පමණි"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"එලාම පමණි"</string>
     <string name="quick_settings_dnd_none_label" msgid="5025477807123029478">"සම්පූර්ණ නිහඬතාව"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"බ්ලූටූත්"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"බ්ලූටූත් (උපාංග <xliff:g id="NUMBER">%d</xliff:g>)"</string>
@@ -356,7 +356,7 @@
     <string name="interruption_level_none_with_warning" msgid="5114872171614161084">"සම්පූර්ණ නිහඬතාව. මෙය තිර කියවන්නන්ද නිහඬ කරනු ඇත."</string>
     <string name="interruption_level_none" msgid="6000083681244492992">"සම්පූර්ණ නිහඬතාව"</string>
     <string name="interruption_level_priority" msgid="6426766465363855505">"ප්‍රමුඛතාව පමණයි"</string>
-    <string name="interruption_level_alarms" msgid="5226306993448328896">"ඇඟවීම් පමණි"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"එලාම පමණි"</string>
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"සම්පූර්ණ\nනිහඬතාව"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ප්‍රමුඛතා\nපමණි"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ඇඟවීම්\nපමණි"</string>
@@ -370,8 +370,8 @@
     <string name="user_add_user" msgid="5110251524486079492">"පරිශීලකයෙක් එක් කරන්න"</string>
     <string name="user_new_user_name" msgid="426540612051178753">"නව පරිශීලකයා"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"අමුත්තා"</string>
-    <string name="guest_new_guest" msgid="600537543078847803">"ආගන්තුකයා එකතු කරන්න"</string>
-    <string name="guest_exit_guest" msgid="7187359342030096885">"අමුත්තාන් ඉවත් කරන්න"</string>
+    <string name="guest_new_guest" msgid="600537543078847803">"අමුත්තා එක් කරන්න"</string>
+    <string name="guest_exit_guest" msgid="7187359342030096885">"අමුත්තා ඉවත් කරන්න"</string>
     <string name="guest_exit_guest_dialog_title" msgid="8480693520521766688">"අමුත්තාන් ඉවත් කරන්නද?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="4155503224769676625">"මෙම සැසියේ සියළුම යෙදුම් සහ දත්ත මකාවී."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7402231963862520531">"ඉවත් කරන්න"</string>
@@ -440,18 +440,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ධාරිතා සංවාදයයි"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"මුල් තත්ත්වය නැවත ප්‍රතිසාධනය කිරීමට තට්ටු කරන්න."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"ඔබ ඔබේ කාර්යාල පැතිකඩ භාවිත කරමින් සිටී"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"ඇමතුම"</item>
-    <item msgid="5997713001067658559">"පද්ධතිය"</item>
-    <item msgid="7858983209929864160">"නාද කරන්න"</item>
-    <item msgid="1850038478268896762">"මාධ්‍ය"</item>
-    <item msgid="8265110906352372092">"එලාමය"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"බ්ලූටූත්"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. නිහඬ කිරීම ඉවත් කිරීමට තට්ටු කරන්න."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. කම්පනය කිරීමට තට්ටු කරන්න. ප්‍රවේශ්‍යතා සේවා නිහඬ කළ හැකිය."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. නිහඬ කිරීමට තට්ටු කරන්න. ප්‍රවේශ්‍යතා සේවා නිහඬ කළ හැකිය."</string>
@@ -602,7 +591,7 @@
     <string name="preview" msgid="9077832302472282938">"පෙරදසුන"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"ටයිල් එක් කිරීමට අදින්න"</string>
     <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ඉවත් කිරීමට මෙතැනට අදින්න"</string>
-    <string name="qs_edit" msgid="2232596095725105230">"සංස්කරණය කරන්න"</string>
+    <string name="qs_edit" msgid="2232596095725105230">"සංස්කරණය"</string>
     <string name="tuner_time" msgid="6572217313285536011">"වේලාව"</string>
   <string-array name="clock_options">
     <item msgid="5965318737560463480">"පැය, මිනිත්තු, සහ තත්පර පෙන්වන්න"</item>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 23daf91..803be7f 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -457,6 +457,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Dostupnosť"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Klepnutím zapnite zvuk."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Klepnutím aktivujte režim vibrovania. Služby dostupnosti je možné stlmiť."</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 90985e7..0f03de9 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -446,18 +446,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> je pogovorno okno glede prostornine"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"Dotaknite se, če želite obnoviti prvotno stanje."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Uporabljate delovni profil"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"Klic"</item>
-    <item msgid="5997713001067658559">"Sistem"</item>
-    <item msgid="7858983209929864160">"Zvonjenje"</item>
-    <item msgid="1850038478268896762">"Predstavnost"</item>
-    <item msgid="8265110906352372092">"Alarm"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"Bluetooth"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Dotaknite se, če želite vklopiti zvok."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Dotaknite se, če želite nastaviti vibriranje. V storitvah za ljudi s posebnimi potrebami bo morda izklopljen zvok."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Dotaknite se, če želite izklopiti zvok. V storitvah za ljudi s posebnimi potrebami bo morda izklopljen zvok."</string>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index 9616c07..c03c0fe 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -440,18 +440,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> është dialogu i volumit"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"Trokit për të restauruar origjinalin."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Po përdor profilin tënd të punës"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"Telefono"</item>
-    <item msgid="5997713001067658559">"Sistemi"</item>
-    <item msgid="7858983209929864160">"Bjeri ziles"</item>
-    <item msgid="1850038478268896762">"Media"</item>
-    <item msgid="8265110906352372092">"Alarmi"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"Bluetooth"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Trokit për të aktivizuar."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Trokit për ta caktuar te dridhja. Shërbimet e qasshmërisë mund të çaktivizohen."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Trokit për të çaktivizuar. Shërbimet e qasshmërisë mund të çaktivizohen."</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 667c65d..fd560de 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -453,6 +453,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Приступачност"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Додирните да бисте укључили звук."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Додирните да бисте подесили на вибрацију. Звук услуга приступачности ће можда бити искључен."</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 0a95017..e0c8472 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Tillgänglighet"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tryck här om du vill slå på ljudet."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tryck här om du vill sätta på vibrationen. Tillgänglighetstjänster kanske inaktiveras."</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index afc5ee4..7c89410 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Zana za walio na matatizo ya kuona au kusikia"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Gonga ili urejeshe."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Gonga ili uweke mtetemo. Huenda ikakomesha huduma za zana za walio na matatizo ya kuona au kusikia."</string>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index 99b8439..bd23b43 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -440,18 +440,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"ஒலியளவு செய்தி: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"அசலை மீட்டமைக்க, தட்டவும்."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"பணி சுயவிவரத்தைப் பயன்படுத்துகிறீர்கள்"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"அழைப்பு"</item>
-    <item msgid="5997713001067658559">"சாதனம்"</item>
-    <item msgid="7858983209929864160">"ரிங்"</item>
-    <item msgid="1850038478268896762">"மீடியா"</item>
-    <item msgid="8265110906352372092">"அலாரம்"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"புளூடூத்"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. ஒலி இயக்க, தட்டவும்."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. அதிர்விற்கு அமைக்க, தட்டவும். அணுகல்தன்மை சேவைகள் ஒலியடக்கப்படக்கூடும்."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. ஒலியடக்க, தட்டவும். அணுகல்தன்மை சேவைகள் ஒலியடக்கப்படக்கூடும்."</string>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index c1aeb09..6ae1e67 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -440,18 +440,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> అనేది వాల్యూమ్ డైలాగ్"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"అసలు దాన్ని పునరుద్ధరించడానికి నొక్కండి."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"మీరు మీ కార్యాలయ ప్రొఫైల్‌ను ఉపయోగిస్తున్నారు"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"కాల్"</item>
-    <item msgid="5997713001067658559">"సిస్టమ్"</item>
-    <item msgid="7858983209929864160">"రింగ్"</item>
-    <item msgid="1850038478268896762">"మీడియా"</item>
-    <item msgid="8265110906352372092">"అలారం"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"బ్లూటూత్"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. అన్‌మ్యూట్ చేయడానికి నొక్కండి."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. వైబ్రేషన్‌కు సెట్ చేయడానికి నొక్కండి. ప్రాప్యత సేవలు మ్యూట్ చేయబడవచ్చు."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. మ్యూట్ చేయడానికి నొక్కండి. ప్రాప్యత సేవలు మ్యూట్ చేయబడవచ్చు."</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 0c461b4..7e2c00f 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -440,18 +440,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> เป็นช่องโต้ตอบระดับเสียง"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"แตะเพื่อคืนค่าเป็นค่าเดิม"</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"คุณกำลังใช้โปรไฟล์งานของคุณ"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"โทร"</item>
-    <item msgid="5997713001067658559">"ระบบ"</item>
-    <item msgid="7858983209929864160">"ทำให้ส่งเสียง"</item>
-    <item msgid="1850038478268896762">"สื่อ"</item>
-    <item msgid="8265110906352372092">"การปลุก"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"บลูทูธ"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s แตะเพื่อเปิดเสียง"</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s แตะเพื่อตั้งค่าให้สั่น อาจมีการปิดเสียงบริการการเข้าถึง"</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s แตะเพื่อปิดเสียง อาจมีการปิดเสียงบริการการเข้าถึง"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index caa9f97..e1e06df 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -440,18 +440,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"Ang <xliff:g id="APP_NAME">%1$s</xliff:g> ang volume dialog"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"I-tap upang i-restore ang orihinal."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Ginagamit mo ang iyong profile sa trabaho"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"Tawag"</item>
-    <item msgid="5997713001067658559">"System"</item>
-    <item msgid="7858983209929864160">"Ipa-ring"</item>
-    <item msgid="1850038478268896762">"Media"</item>
-    <item msgid="8265110906352372092">"Alarm"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"Bluetooth"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. I-tap upang i-unmute."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. I-tap upang itakda na mag-vibrate. Maaaring i-mute ang mga serbisyo sa Accessibility."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. I-tap upang i-mute. Maaaring i-mute ang mga serbisyo sa Accessibility."</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 030c97f..d416fdf 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -440,18 +440,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ses denetimi iletişim kutusu olarak ayarlandı"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"Orijinali geri yüklemek için dokunun."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"İş profilinizi kullanıyorsunuz"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"Çağrı"</item>
-    <item msgid="5997713001067658559">"Sistem"</item>
-    <item msgid="7858983209929864160">"Zili Çaldır"</item>
-    <item msgid="1850038478268896762">"Medya"</item>
-    <item msgid="8265110906352372092">"Alarm"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"Bluetooth"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Sesi açmak için hafifçe dokunun."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Titreşime ayarlamak için hafifçe dokunun. Erişilebilirlik hizmetlerinin sesi kapatılabilir."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Sesi kapatmak için hafifçe dokunun. Erişilebilirlik hizmetlerinin sesi kapatılabilir."</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index c086fff..5db6545 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -457,6 +457,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Спеціальні можливості"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Торкніться, щоб увімкнути звук."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Торкніться, щоб налаштувати вібросигнал. Спеціальні можливості може бути вимкнено."</string>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index ff46ad3..bc89301 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -440,18 +440,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> والیوم ڈائلاگ ہے"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"اصل بحال کرنے کیلئے تھپتھپائیں۔"</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"آپ اپنا دفتری پروفائل استعمال کر رہے ہیں۔"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"کال"</item>
-    <item msgid="5997713001067658559">"سسٹم"</item>
-    <item msgid="7858983209929864160">"رِنگ"</item>
-    <item msgid="1850038478268896762">"میڈیا"</item>
-    <item msgid="8265110906352372092">"الارم"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"بلوٹوتھ"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"‏‎%1$s۔ آواز چالو کرنے کیلئے تھپتھپائیں۔"</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"‏‎%1$s۔ ارتعاش پر سیٹ کرنے کیلئے تھپتھپائیں۔ Accessibility سروسز شاید خاموش ہوں۔"</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"‏‎%1$s۔ خاموش کرنے کیلئے تھپتھپائیں۔ Accessibility سروسز شاید خاموش ہوں۔"</string>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index f2d2661..a71b539 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -453,6 +453,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Maxsus imkoniyatlar"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Ovozini yoqish uchun ustiga bosing."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tebranishni yoqish uchun ustiga bosing. Maxsus imkoniyatlar ishlamasligi mumkin."</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 48b1e4f..d0d8216 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -440,18 +440,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> là hộp thoại khối lượng"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"Nhấn để khôi phục ảnh chụp màn hình gốc."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Bạn đang sử dụng hồ sơ công việc của mình"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"Gọi"</item>
-    <item msgid="5997713001067658559">"Hệ thống"</item>
-    <item msgid="7858983209929864160">"Chuông"</item>
-    <item msgid="1850038478268896762">"Phương tiện"</item>
-    <item msgid="8265110906352372092">"Báo thức"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"Bluetooth"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Nhấn để bật tiếng."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Nhấn để đặt chế độ rung. Bạn có thể tắt tiếng dịch vụ trợ năng."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Nhấn để tắt tiếng. Bạn có thể tắt tiếng dịch vụ trợ năng."</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 94c3af1..7928bf9 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -440,18 +440,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”已用作音量控制对话框"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"点按即可恢复原始设置。"</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"您当前正在使用工作资料"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"通话"</item>
-    <item msgid="5997713001067658559">"系统"</item>
-    <item msgid="7858983209929864160">"铃声"</item>
-    <item msgid="1850038478268896762">"媒体"</item>
-    <item msgid="8265110906352372092">"闹钟"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"蓝牙"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s。点按即可取消静音。"</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s。点按即可设为振动,但可能会同时将无障碍服务设为静音。"</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s。点按即可设为静音,但可能会同时将无障碍服务设为静音。"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 5785af9..b4ea6f8 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -442,18 +442,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」為音量對話框"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"輕按即可復原。"</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"您正在使用工作設定檔"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"通話"</item>
-    <item msgid="5997713001067658559">"系統"</item>
-    <item msgid="7858983209929864160">"鈴聲"</item>
-    <item msgid="1850038478268896762">"媒體"</item>
-    <item msgid="8265110906352372092">"鬧鐘"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"藍牙"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s。輕按即可取消靜音。"</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s。輕按即可設為震動。無障礙功能服務可能已經設為靜音。"</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s。輕按即可設為靜音。無障礙功能服務可能已經設為靜音。"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 6562b39..a6a87f6 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -440,18 +440,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」現在是預設的音量控制對話方塊。"</string>
     <string name="volumeui_notification_text" msgid="8819536904234337445">"輕觸即可恢復原始設定。"</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"您正在使用 Work 設定檔"</string>
-  <string-array name="volume_stream_titles">
-    <item msgid="5841843895402729630">"通話"</item>
-    <item msgid="5997713001067658559">"系統"</item>
-    <item msgid="7858983209929864160">"鈴聲"</item>
-    <item msgid="1850038478268896762">"媒體"</item>
-    <item msgid="8265110906352372092">"鬧鐘"</item>
-    <item msgid="5339394737636839168"></item>
-    <item msgid="2951313578278086204">"藍牙"</item>
-    <item msgid="2919807739709798970"></item>
-    <item msgid="150349973435223405"></item>
-    <item msgid="6761963760295549099"></item>
-  </string-array>
+    <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s。輕觸即可取消靜音。"</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s。輕觸即可設為震動,但系統可能會將無障礙服務一併設為靜音。"</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s。輕觸即可設為靜音,但系統可能會將無障礙服務一併設為靜音。"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index e3c419b..324d306 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -451,6 +451,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Ukufinyeleleka"</item>
   </string-array>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Thepha ukuze ususe ukuthula."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Thepha ukuze usethe ukudlidliza. Amasevisi okufinyelela angathuliswa."</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index b889343..29b5b62 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -84,6 +84,9 @@
     <!-- Height of a the shelf with the notification icons -->
     <dimen name="notification_shelf_height">32dp</dimen>
 
+    <!-- the padding of the shelf icon container -->
+    <dimen name="shelf_icon_container_padding">13dp</dimen>
+
     <!-- The padding of a notification icon on top to the start of the notification. Used for custom
          views where the distance can't be measured -->
     <dimen name="notification_icon_appear_padding">15dp</dimen>
@@ -126,9 +129,6 @@
 
     <dimen name="navigation_key_padding">0dp</dimen>
 
-    <dimen name="navigation_key_width_sw600dp_land">162dp</dimen>
-    <dimen name="navigation_key_padding_sw600dp_land">42dp</dimen>
-
     <!-- The width of the view containing the menu/ime navigation bar icons -->
     <dimen name="navigation_extra_key_width">36dp</dimen>
 
@@ -484,6 +484,9 @@
     <!-- TrustDrawable: Thickness of the circle -->
     <dimen name="trust_circle_thickness">2dp</dimen>
 
+    <!-- How much two taps can be apart to still be recognized as a double tap on the lockscreen -->
+    <dimen name="double_tap_slop">32dp</dimen>
+
     <!-- Margin on the right side of the system icon group on Keyguard. -->
     <fraction name="battery_button_height_fraction">10.5%</fraction>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 5fec647..af1fc59 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -840,6 +840,12 @@
     <!-- Shows when people have pressed the unlock icon to explain how to unlock. [CHAR LIMIT=60] -->
     <string name="keyguard_unlock">Swipe up to unlock</string>
 
+    <!-- Text on keyguard screen indicating that the device is enterprise-managed by a Device Owner [CHAR LIMIT=60] -->
+    <string name="do_disclosure_generic">This device is managed</string>
+
+    <!-- Text on keyguard screen indicating that the device is enterprise-managed by a Device Owner [CHAR LIMIT=40] -->
+    <string name="do_disclosure_with_name">This device is managed by <xliff:g id="organization_name" example="Foo, Inc.">%s</xliff:g></string>
+
     <!-- Shows when people have clicked on the phone icon [CHAR LIMIT=60] -->
     <string name="phone_hint">Swipe from icon for phone</string>
 
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index 664e886..8fc555f 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -313,7 +313,11 @@
         mDataCollector.onNotificationActive();
     }
 
-    public void onNotificationDoubleTap() {
+    public void onNotificationDoubleTap(boolean accepted, float dx, float dy) {
+        if (FalsingLog.ENABLED) {
+            FalsingLog.i("onNotificationDoubleTap", "accepted=" + accepted
+                    + " dx=" + dx + " dy=" + dy + " (px)");
+        }
         mDataCollector.onNotificationDoubleTap();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 2192b8c..c19e806 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -59,6 +59,8 @@
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IKeyguardDrawnCallback;
 import com.android.internal.policy.IKeyguardExitCallback;
@@ -325,6 +327,7 @@
 
     private boolean mWakeAndUnlocking;
     private IKeyguardDrawnCallback mDrawnCallback;
+    private boolean mLockWhenSimRemoved;
 
     KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
 
@@ -415,7 +418,7 @@
                 case ABSENT:
                     // only force lock screen in case of missing sim if user hasn't
                     // gone through setup wizard
-                    synchronized (this) {
+                    synchronized (KeyguardViewMediator.this) {
                         if (shouldWaitForProvisioning()) {
                             if (!mShowing) {
                                 if (DEBUG_SIM_STATES) Log.d(TAG, "ICC_ABSENT isn't showing,"
@@ -426,11 +429,12 @@
                                 resetStateLocked();
                             }
                         }
+                        onSimNotReadyLocked();
                     }
                     break;
                 case PIN_REQUIRED:
                 case PUK_REQUIRED:
-                    synchronized (this) {
+                    synchronized (KeyguardViewMediator.this) {
                         if (!mShowing) {
                             if (DEBUG_SIM_STATES) Log.d(TAG,
                                     "INTENT_VALUE_ICC_LOCKED and keygaurd isn't "
@@ -442,7 +446,7 @@
                     }
                     break;
                 case PERM_DISABLED:
-                    synchronized (this) {
+                    synchronized (KeyguardViewMediator.this) {
                         if (!mShowing) {
                             if (DEBUG_SIM_STATES) Log.d(TAG, "PERM_DISABLED and "
                                   + "keygaurd isn't showing.");
@@ -452,21 +456,40 @@
                                   + "show permanently disabled message in lockscreen.");
                             resetStateLocked();
                         }
+                        onSimNotReadyLocked();
                     }
                     break;
                 case READY:
-                    synchronized (this) {
+                    synchronized (KeyguardViewMediator.this) {
                         if (mShowing) {
                             resetStateLocked();
                         }
+                        mLockWhenSimRemoved = true;
                     }
                     break;
                 default:
-                    if (DEBUG_SIM_STATES) Log.v(TAG, "Ignoring state: " + simState);
+                    if (DEBUG_SIM_STATES) Log.v(TAG, "Unspecific state: " + simState);
+                    synchronized (KeyguardViewMediator.this) {
+                        onSimNotReadyLocked();
+                    }
                     break;
             }
         }
 
+        private void onSimNotReadyLocked() {
+            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");
+                    doKeyguardLocked(null);
+                } else {
+                    resetStateLocked();
+                }
+            }
+        }
+
         @Override
         public void onFingerprintAuthFailed() {
             final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
@@ -1775,7 +1798,6 @@
                 // (like recents). Temporary enable/disable (e.g. the "back" button) are
                 // done in KeyguardHostView.
                 flags |= StatusBarManager.DISABLE_RECENT;
-                flags |= StatusBarManager.DISABLE_SEARCH;
             }
             if (isShowingAndNotOccluded()) {
                 flags |= StatusBarManager.DISABLE_HOME;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 7655e6c..790f3f6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -438,9 +438,9 @@
         SystemServicesProxy ssp = Recents.getSystemServices();
         ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
         boolean screenPinningActive = ssp.isScreenPinningActive();
-        boolean isRunningTaskInHomeStack = runningTask != null &&
-                SystemServicesProxy.isHomeStack(runningTask.stackId);
-        if (runningTask != null && !isRunningTaskInHomeStack && !screenPinningActive) {
+        boolean isRunningTaskInHomeOrRecentsStack = runningTask != null &&
+                ActivityManager.StackId.isHomeOrRecentsStack(runningTask.stackId);
+        if (runningTask != null && !isRunningTaskInHomeOrRecentsStack && !screenPinningActive) {
             logDockAttempt(mContext, runningTask.topActivity, runningTask.resizeMode);
             if (runningTask.isDockable) {
                 if (metricsDockAction != -1) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index abde44e..c9c4f2b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -18,6 +18,8 @@
 
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
+import static android.app.ActivityManager.StackId.isHomeOrRecentsStack;
 import static android.view.View.MeasureSpec;
 
 import android.app.ActivityManager;
@@ -460,8 +462,8 @@
         // Return early if there is no running task (can't determine affiliated tasks in this case)
         ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
         if (runningTask == null) return;
-        // Return early if the running task is in the home stack (optimization)
-        if (SystemServicesProxy.isHomeStack(runningTask.stackId)) return;
+        // Return early if the running task is in the home/recents stack (optimization)
+        if (isHomeOrRecentsStack(runningTask.stackId)) return;
 
         // Find the task in the recents list
         ArrayList<Task> tasks = focusedStack.getStackTasks();
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 2272a72..ea50d89 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -321,7 +321,7 @@
         // Remove home/recents/excluded tasks
         int minNumTasksToQuery = 10;
         int numTasksToQuery = Math.max(minNumTasksToQuery, numLatestTasks);
-        int flags = ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS |
+        int flags = ActivityManager.RECENT_IGNORE_HOME_AND_RECENTS_STACK_TASKS |
                 ActivityManager.RECENT_INGORE_DOCKED_STACK_TOP_TASK |
                 ActivityManager.RECENT_INGORE_PINNED_STACK_TASKS |
                 ActivityManager.RECENT_IGNORE_UNAVAILABLE |
@@ -399,21 +399,23 @@
         if (mIam == null) return false;
 
         try {
-            ActivityManager.StackInfo stackInfo = mIam.getStackInfo(
+            ActivityManager.StackInfo homeStackInfo = mIam.getStackInfo(
                     ActivityManager.StackId.HOME_STACK_ID);
             ActivityManager.StackInfo fullscreenStackInfo = mIam.getStackInfo(
                     ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID);
-            ComponentName topActivity = stackInfo.topActivity;
-            boolean homeStackVisibleNotOccluded = stackInfo.visible;
-            if (fullscreenStackInfo != null) {
-                boolean isFullscreenStackOccludingHome = fullscreenStackInfo.visible &&
-                        fullscreenStackInfo.position > stackInfo.position;
-                homeStackVisibleNotOccluded &= !isFullscreenStackOccludingHome;
-            }
+            ActivityManager.StackInfo recentsStackInfo = mIam.getStackInfo(
+                    ActivityManager.StackId.RECENTS_STACK_ID);
+
+            boolean homeStackVisibleNotOccluded = isStackNotOccluded(homeStackInfo,
+                    fullscreenStackInfo);
+            boolean recentsStackVisibleNotOccluded = isStackNotOccluded(recentsStackInfo,
+                    fullscreenStackInfo);
             if (isHomeStackVisible != null) {
                 isHomeStackVisible.value = homeStackVisibleNotOccluded;
             }
-            return (homeStackVisibleNotOccluded && topActivity != null
+            ComponentName topActivity = recentsStackInfo != null ?
+                    recentsStackInfo.topActivity : null;
+            return (recentsStackVisibleNotOccluded && topActivity != null
                     && topActivity.getPackageName().equals(RecentsImpl.RECENTS_PACKAGE)
                     && Recents.RECENTS_ACTIVITIES.contains(topActivity.getClassName()));
         } catch (RemoteException e) {
@@ -422,6 +424,17 @@
         return false;
     }
 
+    private boolean isStackNotOccluded(ActivityManager.StackInfo stackInfo,
+            ActivityManager.StackInfo fullscreenStackInfo) {
+        boolean stackVisibleNotOccluded = stackInfo == null || stackInfo.visible;
+        if (fullscreenStackInfo != null && stackInfo != null) {
+            boolean isFullscreenStackOccludingg = fullscreenStackInfo.visible &&
+                    fullscreenStackInfo.position > stackInfo.position;
+            stackVisibleNotOccluded &= !isFullscreenStackOccludingg;
+        }
+        return stackVisibleNotOccluded;
+    }
+
     /**
      * Returns whether this device has freeform workspaces.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index d789477..0eef864 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -323,7 +323,8 @@
             // Create the intent to show the screenshot in gallery
             Intent launchIntent = new Intent(Intent.ACTION_VIEW);
             launchIntent.setDataAndType(mParams.imageUri, "image/png");
-            launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            launchIntent.setFlags(
+                    Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION);
 
             final long now = System.currentTimeMillis();
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 173f160..d46d267 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -116,6 +116,10 @@
     private float mDownY;
     private final float mTouchSlop;
 
+    private float mActivationX;
+    private float mActivationY;
+    private final float mDoubleTapSlop;
+
     private OnActivatedListener mOnActivatedListener;
 
     private final Interpolator mSlowOutFastInInterpolator;
@@ -179,6 +183,7 @@
     public ActivatableNotificationView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+        mDoubleTapSlop = context.getResources().getDimension(R.dimen.double_tap_slop);
         mSlowOutFastInInterpolator = new PathInterpolator(0.8f, 0.0f, 0.6f, 1.0f);
         mSlowOutLinearInInterpolator = new PathInterpolator(0.8f, 0.0f, 1.0f, 1.0f);
         setClipChildren(false);
@@ -240,7 +245,6 @@
             boolean wasActivated = mActivated;
             result = handleTouchEventDimmed(event);
             if (wasActivated && result && event.getAction() == MotionEvent.ACTION_UP) {
-                mFalsingManager.onNotificationDoubleTap();
                 removeCallbacks(mTapTimeoutRunnable);
             }
         } else {
@@ -291,9 +295,21 @@
                     if (!mActivated) {
                         makeActive();
                         postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS);
+                        mActivationX = event.getX();
+                        mActivationY = event.getY();
                     } else {
-                        if (!performClick()) {
-                            return false;
+                        boolean withinDoubleTapSlop = isWithinDoubleTapSlop(event);
+                        mFalsingManager.onNotificationDoubleTap(
+                                withinDoubleTapSlop,
+                                event.getX() - mActivationX,
+                                event.getY() - mActivationY);
+                        if (withinDoubleTapSlop) {
+                            if (!performClick()) {
+                                return false;
+                            }
+                        } else {
+                            makeInactive(true /* animate */);
+                            mTrackTouch = false;
                         }
                     }
                 } else {
@@ -401,6 +417,16 @@
                 && Math.abs(event.getY() - mDownY) < mTouchSlop;
     }
 
+    private boolean isWithinDoubleTapSlop(MotionEvent event) {
+        if (!mActivated) {
+            // If we're not activated there's no double tap slop to satisfy.
+            return true;
+        }
+
+        return Math.abs(event.getX() - mActivationX) < mDoubleTapSlop
+                && Math.abs(event.getY() - mActivationY) < mDoubleTapSlop;
+    }
+
     public void setDimmed(boolean dimmed, boolean fade) {
         if (mDimmed != dimmed) {
             mDimmed = dimmed;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index f5ca678..414ebec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1073,8 +1073,8 @@
         int appUid = -1;
         try {
             final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
-                    PackageManager.GET_UNINSTALLED_PACKAGES
-                            | PackageManager.GET_DISABLED_COMPONENTS);
+                    PackageManager.MATCH_UNINSTALLED_PACKAGES
+                            | PackageManager.MATCH_DISABLED_COMPONENTS);
             if (info != null) {
                 appname = String.valueOf(pmUser.getApplicationLabel(info));
                 pkgicon = pmUser.getApplicationIcon(info);
@@ -1643,8 +1643,8 @@
             String appname = pkg;
             try {
                 final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
-                        PackageManager.GET_UNINSTALLED_PACKAGES
-                                | PackageManager.GET_DISABLED_COMPONENTS);
+                        PackageManager.MATCH_UNINSTALLED_PACKAGES
+                                | PackageManager.MATCH_DISABLED_COMPONENTS);
                 if (info != null) {
                     appname = String.valueOf(pmUser.getApplicationLabel(info));
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index a1384dcb..661cc3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -1685,6 +1685,9 @@
         if (mGuts != null) {
             mGuts.setClipBottomAmount(clipBottomAmount);
         }
+        if (mChildrenContainer != null) {
+            mChildrenContainer.setClipBottomAmount(clipBottomAmount);
+        }
     }
 
     public boolean isMaxExpandHeightInitialized() {
@@ -1863,9 +1866,6 @@
             super.applyToView(view);
             if (view instanceof ExpandableNotificationRow) {
                 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
-                if (this.isBottomClipped) {
-                    row.setClipToActualHeight(true);
-                }
                 row.applyChildrenState(mOverallState);
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index 4b95f07..91abc87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -41,7 +41,7 @@
                 outline.setRect(translation,
                         mClipTopAmount,
                         getWidth() + translation,
-                        Math.max(getActualHeight(), mClipTopAmount));
+                        Math.max(getActualHeight() - mClipBottomAmount, mClipTopAmount));
             } else {
                 outline.setRect(mOutlineRect);
             }
@@ -66,6 +66,12 @@
         invalidateOutline();
     }
 
+    @Override
+    public void setClipBottomAmount(int clipBottomAmount) {
+        super.setClipBottomAmount(clipBottomAmount);
+        invalidateOutline();
+    }
+
     protected void setOutlineAlpha(float alpha) {
         if (alpha != mOutlineAlpha) {
             mOutlineAlpha = alpha;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 0f5981b..37a900e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -38,7 +38,7 @@
     protected OnHeightChangedListener mOnHeightChangedListener;
     private int mActualHeight;
     protected int mClipTopAmount;
-    private float mClipBottomAmount;
+    protected int mClipBottomAmount;
     private boolean mDark;
     private ArrayList<View> mMatchParentViews = new ArrayList<View>();
     private static Rect mClipRect = new Rect();
@@ -241,7 +241,7 @@
         return mClipTopAmount;
     }
 
-    public float getClipBottomAmount() {
+    public int getClipBottomAmount() {
         return mClipBottomAmount;
     }
 
@@ -354,11 +354,8 @@
     private void updateClipping() {
         if (mClipToActualHeight) {
             int top = getClipTopAmount();
-            if (top >= getActualHeight()) {
-                top = getActualHeight() - 1;
-            }
-            mClipRect.set(0, top, getWidth(), (int) (getActualHeight() + getExtraBottomPadding()
-                                - mClipBottomAmount));
+            mClipRect.set(0, top, getWidth(), Math.max(getActualHeight() + getExtraBottomPadding()
+                                - mClipBottomAmount, top));
             setClipBounds(mClipRect);
         } else {
             setClipBounds(null);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 0ef97152..218c1bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar;
 
 import android.app.ActivityManager;
+import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -36,6 +37,7 @@
 import android.text.format.Formatter;
 import android.util.Log;
 import android.view.View;
+import android.view.ViewGroup;
 
 import com.android.internal.app.IBatteryStats;
 import com.android.keyguard.KeyguardUpdateMonitor;
@@ -58,7 +60,9 @@
     private static final long TRANSIENT_FP_ERROR_TIMEOUT = 1300;
 
     private final Context mContext;
+    private final ViewGroup mIndicationArea;
     private final KeyguardIndicationTextView mTextView;
+    private final KeyguardIndicationTextView mDisclosure;
     private final UserManager mUserManager;
     private final IBatteryStats mBatteryInfo;
 
@@ -78,10 +82,16 @@
     private int mChargingWattage;
     private String mMessageToShowOnScreenOn;
 
-    public KeyguardIndicationController(Context context, KeyguardIndicationTextView textView,
-                                        LockIcon lockIcon) {
+    private final DevicePolicyManager mDevicePolicyManager;
+
+    public KeyguardIndicationController(Context context, ViewGroup indicationArea,
+            LockIcon lockIcon) {
         mContext = context;
-        mTextView = textView;
+        mIndicationArea = indicationArea;
+        mTextView = (KeyguardIndicationTextView) indicationArea.findViewById(
+                R.id.keyguard_indication_text);
+        mDisclosure = (KeyguardIndicationTextView) indicationArea.findViewById(
+                R.id.keyguard_indication_enterprise_disclosure);
         mLockIcon = lockIcon;
 
         Resources res = context.getResources();
@@ -92,14 +102,39 @@
         mBatteryInfo = IBatteryStats.Stub.asInterface(
                 ServiceManager.getService(BatteryStats.SERVICE_NAME));
 
+        mDevicePolicyManager = (DevicePolicyManager) context.getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
+
         KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateMonitor);
         context.registerReceiverAsUser(mTickReceiver, UserHandle.SYSTEM,
                 new IntentFilter(Intent.ACTION_TIME_TICK), null, null);
+
+        updateDisclosure();
+    }
+
+    private void updateDisclosure() {
+        if (mDevicePolicyManager == null) {
+            return;
+        }
+
+        if (mDevicePolicyManager.isDeviceManaged()) {
+            final CharSequence organizationName =
+                    mDevicePolicyManager.getDeviceOwnerOrganizationName();
+            if (organizationName != null) {
+                mDisclosure.switchIndication(mContext.getResources().getString(
+                        R.string.do_disclosure_with_name, organizationName));
+            } else {
+                mDisclosure.switchIndication(R.string.do_disclosure_generic);
+            }
+            mDisclosure.setVisibility(View.VISIBLE);
+        } else {
+            mDisclosure.setVisibility(View.GONE);
+        }
     }
 
     public void setVisible(boolean visible) {
         mVisible = visible;
-        mTextView.setVisibility(visible ? View.VISIBLE : View.GONE);
+        mIndicationArea.setVisibility(visible ? View.VISIBLE : View.GONE);
         if (visible) {
             hideTransientIndication();
             updateIndication();
@@ -242,6 +277,13 @@
         }
 
         @Override
+        public void onKeyguardVisibilityChanged(boolean showing) {
+            if (showing) {
+                updateDisclosure();
+            }
+        }
+
+        @Override
         public void onFingerprintHelp(int msgId, String helpString) {
             KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
             if (!updateMonitor.isUnlockingWithFingerprintAllowed()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 6b9a89ef..680562a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -95,6 +95,12 @@
                 R.dimen.status_bar_padding_start);
         mPaddingBetweenElements = getResources().getDimensionPixelSize(
                 R.dimen.notification_divider_height);
+        ViewGroup.LayoutParams layoutParams = getLayoutParams();
+        layoutParams.height = getResources().getDimensionPixelOffset(
+                R.dimen.notification_shelf_height);
+        setLayoutParams(layoutParams);
+        int padding = getResources().getDimensionPixelOffset(R.dimen.shelf_icon_container_padding);
+        mShelfIcons.setPadding(padding, 0, padding, 0);
     }
 
     @Override
@@ -150,7 +156,6 @@
             mShelfState.alpha = 1.0f;
             mShelfState.belowSpeedBump = mAmbientState.getSpeedBumpIndex() == 0;
             mShelfState.shadowAlpha = 1.0f;
-            mShelfState.isBottomClipped = false;
             mShelfState.hideSensitive = false;
             mShelfState.xTranslation = getTranslationX();
             if (mNotGoneIndex != -1) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
index f6fe176..c9f7456 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
@@ -40,6 +40,7 @@
     private int mImageResource = -1;
     private Drawable mImageDrawable;
     private View mCurrentView;
+    private boolean mVertical;
 
     public ButtonDispatcher(int id) {
         mId = id;
@@ -49,13 +50,6 @@
         mViews.clear();
     }
 
-    void addView(View view, boolean landscape) {
-        addView(view);
-        if (view instanceof ButtonInterface) {
-            ((ButtonInterface) view).setLandscape(landscape);
-        }
-    }
-
     void addView(View view) {
         mViews.add(view);
         view.setOnClickListener(mClickListener);
@@ -75,6 +69,10 @@
         } else if (mImageDrawable != null) {
             ((ButtonInterface) view).setImageDrawable(mImageDrawable);
         }
+
+        if (view instanceof  ButtonInterface) {
+            ((ButtonInterface) view).setVertical(mVertical);
+        }
     }
 
     public int getId() {
@@ -186,4 +184,15 @@
         }
     }
 
+    public void setVertical(boolean vertical) {
+        mVertical = vertical;
+        final int N = mViews.size();
+        for (int i = 0; i < N; i++) {
+            final View view = mViews.get(i);
+            if (view instanceof ButtonInterface) {
+                ((ButtonInterface) view).setVertical(vertical);
+            }
+        }
+    }
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 89defec..daa57c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -107,6 +107,8 @@
     private KeyguardAffordanceView mRightAffordanceView;
     private KeyguardAffordanceView mLeftAffordanceView;
     private LockIcon mLockIcon;
+    private ViewGroup mIndicationArea;
+    private TextView mEnterpriseDisclosure;
     private TextView mIndicationText;
     private ViewGroup mPreviewContainer;
 
@@ -208,6 +210,9 @@
         mRightAffordanceView = (KeyguardAffordanceView) findViewById(R.id.camera_button);
         mLeftAffordanceView = (KeyguardAffordanceView) findViewById(R.id.left_button);
         mLockIcon = (LockIcon) findViewById(R.id.lock_icon);
+        mIndicationArea = (ViewGroup) findViewById(R.id.keyguard_indication_area);
+        mEnterpriseDisclosure = (TextView) findViewById(
+                R.id.keyguard_indication_enterprise_disclosure);
         mIndicationText = (TextView) findViewById(R.id.keyguard_indication_text);
         watchForCameraPolicyChanges();
         updateCameraVisibility();
@@ -252,13 +257,16 @@
         super.onConfigurationChanged(newConfig);
         int indicationBottomMargin = getResources().getDimensionPixelSize(
                 R.dimen.keyguard_indication_margin_bottom);
-        MarginLayoutParams mlp = (MarginLayoutParams) mIndicationText.getLayoutParams();
+        MarginLayoutParams mlp = (MarginLayoutParams) mIndicationArea.getLayoutParams();
         if (mlp.bottomMargin != indicationBottomMargin) {
             mlp.bottomMargin = indicationBottomMargin;
-            mIndicationText.setLayoutParams(mlp);
+            mIndicationArea.setLayoutParams(mlp);
         }
 
         // Respect font size setting.
+        mEnterpriseDisclosure.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+                getResources().getDimensionPixelSize(
+                        com.android.internal.R.dimen.text_size_small_material));
         mIndicationText.setTextSize(TypedValue.COMPLEX_UNIT_PX,
                 getResources().getDimensionPixelSize(
                         com.android.internal.R.dimen.text_size_small_material));
@@ -595,8 +603,8 @@
         return mLockIcon;
     }
 
-    public View getIndicationView() {
-        return mIndicationText;
+    public View getIndicationArea() {
+        return mIndicationArea;
     }
 
     @Override
@@ -658,8 +666,8 @@
         if (mRightAffordanceView.getVisibility() == View.VISIBLE) {
             startFinishDozeAnimationElement(mRightAffordanceView, delay);
         }
-        mIndicationText.setAlpha(0f);
-        mIndicationText.animate()
+        mIndicationArea.setAlpha(0f);
+        mIndicationArea.animate()
                 .alpha(1f)
                 .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
                 .setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index c420927..b2b093c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -17,12 +17,14 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.util.AttributeSet;
 import android.util.SparseArray;
+import android.view.Display;
+import android.view.Display.Mode;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.WindowManager;
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 import android.widget.Space;
@@ -72,12 +74,13 @@
 
     protected FrameLayout mRot0;
     protected FrameLayout mRot90;
+    private boolean isRot0Landscape;
 
     private SparseArray<ButtonDispatcher> mButtonDispatchers;
     private String mCurrentLayout;
 
-    private View mLastRot0;
-    private View mLastRot90;
+    private View mLastPortrait;
+    private View mLastLandscape;
 
     private boolean mAlternativeOrder;
 
@@ -85,6 +88,10 @@
         super(context, attrs);
         mDensity = context.getResources().getConfiguration().densityDpi;
         createInflaters();
+        Display display = ((WindowManager)
+                context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
+        Mode displayMode = display.getMode();
+        isRot0Landscape = displayMode.getPhysicalWidth() > displayMode.getPhysicalHeight();
     }
 
     private void createInflaters() {
@@ -215,17 +222,17 @@
         String[] center = sets[1].split(BUTTON_SEPARATOR);
         String[] end = sets[2].split(BUTTON_SEPARATOR);
         // Inflate these in start to end order or accessibility traversal will be messed up.
-        inflateButtons(start, (ViewGroup) mRot0.findViewById(R.id.ends_group), false);
-        inflateButtons(start, (ViewGroup) mRot90.findViewById(R.id.ends_group), true);
+        inflateButtons(start, (ViewGroup) mRot0.findViewById(R.id.ends_group), isRot0Landscape);
+        inflateButtons(start, (ViewGroup) mRot90.findViewById(R.id.ends_group), !isRot0Landscape);
 
-        inflateButtons(center, (ViewGroup) mRot0.findViewById(R.id.center_group), false);
-        inflateButtons(center, (ViewGroup) mRot90.findViewById(R.id.center_group), true);
+        inflateButtons(center, (ViewGroup) mRot0.findViewById(R.id.center_group), isRot0Landscape);
+        inflateButtons(center, (ViewGroup) mRot90.findViewById(R.id.center_group), !isRot0Landscape);
 
         addGravitySpacer((LinearLayout) mRot0.findViewById(R.id.ends_group));
         addGravitySpacer((LinearLayout) mRot90.findViewById(R.id.ends_group));
 
-        inflateButtons(end, (ViewGroup) mRot0.findViewById(R.id.ends_group), false);
-        inflateButtons(end, (ViewGroup) mRot90.findViewById(R.id.ends_group), true);
+        inflateButtons(end, (ViewGroup) mRot0.findViewById(R.id.ends_group), isRot0Landscape);
+        inflateButtons(end, (ViewGroup) mRot90.findViewById(R.id.ends_group), !isRot0Landscape);
     }
 
     private void addGravitySpacer(LinearLayout layout) {
@@ -234,7 +241,7 @@
 
     private void inflateButtons(String[] buttons, ViewGroup parent, boolean landscape) {
         for (int i = 0; i < buttons.length; i++) {
-            inflateButton(buttons[i], parent, landscape, i);
+            inflateButton(buttons[i], parent, landscape);
         }
     }
 
@@ -247,8 +254,7 @@
     }
 
     @Nullable
-    protected View inflateButton(String buttonSpec, ViewGroup parent, boolean landscape,
-            int indexInParent) {
+    protected View inflateButton(String buttonSpec, ViewGroup parent, boolean landscape) {
         LayoutInflater inflater = landscape ? mLandscapeInflater : mLayoutInflater;
         float size = extractSize(buttonSpec);
         View v = createView(buttonSpec, parent, inflater, landscape);
@@ -259,15 +265,15 @@
             params.width = (int) (params.width * size);
         }
         parent.addView(v);
-        addToDispatchers(v, landscape);
-        View lastView = landscape ? mLastRot90 : mLastRot0;
+        addToDispatchers(v);
+        View lastView = landscape ? mLastLandscape : mLastPortrait;
         if (lastView != null) {
             v.setAccessibilityTraversalAfter(lastView.getId());
         }
         if (landscape) {
-            mLastRot90 = v;
+            mLastLandscape = v;
         } else {
-            mLastRot0 = v;
+            mLastPortrait = v;
         }
         return v;
     }
@@ -283,19 +289,10 @@
         }
         if (HOME.equals(button)) {
             v = inflater.inflate(R.layout.home, parent, false);
-            if (landscape && isSw600Dp()) {
-                setupLandButton(v);
-            }
         } else if (BACK.equals(button)) {
             v = inflater.inflate(R.layout.back, parent, false);
-            if (landscape && isSw600Dp()) {
-                setupLandButton(v);
-            }
         } else if (RECENT.equals(button)) {
             v = inflater.inflate(R.layout.recent_apps, parent, false);
-            if (landscape && isSw600Dp()) {
-                setupLandButton(v);
-            }
         } else if (MENU_IME.equals(button)) {
             v = inflater.inflate(R.layout.menu_ime, parent, false);
         } else if (NAVSPACE.equals(button)) {
@@ -348,37 +345,22 @@
         return buttonSpec.substring(0, buttonSpec.indexOf(SIZE_MOD_START));
     }
 
-    private void addToDispatchers(View v, boolean landscape) {
+    private void addToDispatchers(View v) {
         if (mButtonDispatchers != null) {
             final int indexOfKey = mButtonDispatchers.indexOfKey(v.getId());
             if (indexOfKey >= 0) {
-                mButtonDispatchers.valueAt(indexOfKey).addView(v, landscape);
+                mButtonDispatchers.valueAt(indexOfKey).addView(v);
             } else if (v instanceof ViewGroup) {
                 final ViewGroup viewGroup = (ViewGroup)v;
                 final int N = viewGroup.getChildCount();
                 for (int i = 0; i < N; i++) {
-                    addToDispatchers(viewGroup.getChildAt(i), landscape);
+                    addToDispatchers(viewGroup.getChildAt(i));
                 }
             }
         }
     }
 
-    private boolean isSw600Dp() {
-        Configuration configuration = mContext.getResources().getConfiguration();
-        return (configuration.smallestScreenWidthDp >= 600);
-    }
 
-    /**
-     * This manually sets the width of sw600dp landscape buttons because despite
-     * overriding the configuration from the overridden resources aren't loaded currently.
-     */
-    private void setupLandButton(View v) {
-        Resources res = mContext.getResources();
-        v.getLayoutParams().width = res.getDimensionPixelOffset(
-                R.dimen.navigation_key_width_sw600dp_land);
-        int padding = res.getDimensionPixelOffset(R.dimen.navigation_key_padding_sw600dp_land);
-        v.setPadding(padding, v.getPaddingTop(), padding, v.getPaddingBottom());
-    }
 
     private void clearViews() {
         if (mButtonDispatchers != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 97df237..7023324 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -577,6 +577,7 @@
         getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
 
         mDeadZone = (DeadZone) mCurrentView.findViewById(R.id.deadzone);
+        mDeadZone.setDisplayRotation(mCurrentRotation);
 
         // force the low profile & disabled states into compliance
         mBarTransitions.init();
@@ -589,6 +590,8 @@
 
         updateTaskSwitchHelper();
         setNavigationIconHints(mNavigationIconHints, true);
+
+        getHomeButton().setVertical(mVertical);
     }
 
     public void onKeyguardOccludedChanged(boolean keyguardOccluded) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 0dbff19..d543f49 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -8,7 +8,7 @@
 import android.support.annotation.NonNull;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.widget.LinearLayout;
+import android.widget.FrameLayout;
 
 import com.android.internal.util.NotificationColorUtil;
 import com.android.systemui.R;
@@ -73,16 +73,18 @@
 
     public void onDensityOrFontScaleChanged(Context context) {
         reloadDimens(context);
-        final LinearLayout.LayoutParams params = generateIconLayoutParams();
+        final FrameLayout.LayoutParams params = generateIconLayoutParams();
         for (int i = 0; i < mNotificationIcons.getChildCount(); i++) {
             View child = mNotificationIcons.getChildAt(i);
             child.setLayoutParams(params);
+            child = mShelfIcons.getChildAt(i);
+            child.setLayoutParams(params);
         }
     }
 
     @NonNull
-    private LinearLayout.LayoutParams generateIconLayoutParams() {
-        return new LinearLayout.LayoutParams(
+    private FrameLayout.LayoutParams generateIconLayoutParams() {
+        return new FrameLayout.LayoutParams(
                 mIconSize + 2 * mIconHPadding, getHeight());
     }
 
@@ -203,7 +205,7 @@
             hostLayout.removeView(toRemove.get(i));
         }
 
-        final LinearLayout.LayoutParams params = generateIconLayoutParams();
+        final FrameLayout.LayoutParams params = generateIconLayoutParams();
         for (int i = 0; i < toShow.size(); i++) {
             View v = toShow.get(i);
             // The view might still be transiently added if it was just removed and added again
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 2895890..03697b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -48,7 +48,7 @@
             return mAnimationFilter;
         }
     }.setDuration(200);
-    
+
     private static final AnimationProperties ADD_ICON_PROPERTIES = new AnimationProperties() {
         private AnimationFilter mAnimationFilter = new AnimationFilter().animateAlpha();
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 523528d..99e98f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -404,12 +404,9 @@
                 mKeyguardStatusView.getHeight());
         int notificationPadding = Math.max(1, getResources().getDimensionPixelSize(
                 R.dimen.notification_divider_height));
-        final int overflowheight = getResources().getDimensionPixelSize(
-                R.dimen.notification_shelf_height);
         float shelfSize = mNotificationStackScroller.getNotificationShelf().getIntrinsicHeight()
                 + notificationPadding;
-        float availableSpace = mNotificationStackScroller.getHeight() - minPadding - overflowheight
-                - shelfSize;
+        float availableSpace = mNotificationStackScroller.getHeight() - minPadding - shelfSize;
         int count = 0;
         for (int i = 0; i < mNotificationStackScroller.getChildCount(); i++) {
             ExpandableView child = (ExpandableView) mNotificationStackScroller.getChildAt(i);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 570d5d4..f16c834 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -1006,14 +1006,14 @@
         });
         animator.start();
         mHeightAnimator = animator;
-        mKeyguardBottomArea.getIndicationView().animate()
+        mKeyguardBottomArea.getIndicationArea().animate()
                 .translationY(-mHintDistance)
                 .setDuration(250)
                 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
                 .withEndAction(new Runnable() {
                     @Override
                     public void run() {
-                        mKeyguardBottomArea.getIndicationView().animate()
+                        mKeyguardBottomArea.getIndicationArea().animate()
                                 .translationY(0)
                                 .setDuration(450)
                                 .setInterpolator(mBounceInterpolator)
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 bb86d6f..2b74c84 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -857,8 +857,7 @@
         mKeyguardBottomArea.setActivityStarter(this);
         mKeyguardBottomArea.setAssistManager(mAssistManager);
         mKeyguardIndicationController = new KeyguardIndicationController(mContext,
-                (KeyguardIndicationTextView) mStatusBarWindow.findViewById(
-                        R.id.keyguard_indication_text),
+                (ViewGroup) mStatusBarWindow.findViewById(R.id.keyguard_indication_area),
                 mKeyguardBottomArea.getLockIcon());
         mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController);
 
@@ -1074,7 +1073,6 @@
         updateClearAll();
         inflateEmptyShadeView();
         updateEmptyShadeView();
-        inflateShelf();
         mStatusBarKeyguardViewManager.onDensityOrFontScaleChanged();
         mUserInfoController.onDensityOrFontScaleChanged();
         if (mUserSwitcherController != null) {
@@ -1874,6 +1872,9 @@
 
         updateQsExpansionEnabled();
         mShadeUpdates.check();
+
+        // Let's also update the icons
+        mIconController.updateNotificationIcons(mNotificationData);
     }
 
     /**
@@ -2022,7 +2023,6 @@
         mNotificationData.filterAndSort();
 
         updateNotificationShade();
-        mIconController.updateNotificationIcons(mNotificationData);
     }
 
     public void requestNotificationUpdate() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
index 1cad61f..4c879c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
@@ -24,6 +24,7 @@
 import android.util.AttributeSet;
 import android.util.Slog;
 import android.view.MotionEvent;
+import android.view.Surface;
 import android.view.View;
 
 import com.android.systemui.R;
@@ -54,6 +55,7 @@
     private int mHold, mDecay;
     private boolean mVertical;
     private long mLastPokeTime;
+    private int mDisplayRotation;
 
     private final Runnable mDebugFlash = new Runnable() {
         @Override
@@ -132,7 +134,16 @@
             int size = (int) getSize(event.getEventTime());
             // In the vertical orientation consume taps along the left edge.
             // In horizontal orientation consume taps along the top edge.
-            final boolean consumeEvent = mVertical ? event.getX() < size : event.getY() < size;
+            final boolean consumeEvent;
+            if (mVertical) {
+                if (mDisplayRotation == Surface.ROTATION_270) {
+                    consumeEvent = event.getX() > getWidth() - size;
+                } else {
+                    consumeEvent = event.getX() < size;
+                }
+            } else {
+                consumeEvent = event.getY() < size;
+            }
             if (consumeEvent) {
                 if (CHATTY) {
                     Slog.v(TAG, "consuming errant click: (" + event.getX() + "," + event.getY() + ")");
@@ -170,7 +181,16 @@
         }
 
         final int size = (int) getSize(SystemClock.uptimeMillis());
-        can.clipRect(0, 0, mVertical ? size : can.getWidth(), mVertical ? can.getHeight() : size);
+        if (mVertical) {
+            if (mDisplayRotation == Surface.ROTATION_270) {
+                can.clipRect(can.getWidth() - size, 0, can.getWidth(), can.getHeight());
+            } else {
+                can.clipRect(0, 0, size, can.getHeight());
+            }
+        } else {
+            can.clipRect(0, 0, can.getWidth(), size);
+        }
+
         final float frac = DEBUG ? (mFlashFrac - 0.5f) + 0.5f : mFlashFrac;
         can.drawARGB((int) (frac * 0xFF), 0xDD, 0xEE, 0xAA);
 
@@ -178,4 +198,8 @@
             // crazy aggressive redrawing here, for debugging only
             postInvalidateDelayed(100);
     }
+
+    public void setDisplayRotation(int rotation) {
+        mDisplayRotation = rotation;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index bcc5a3f..ae59315 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -275,7 +275,7 @@
     }
 
     @Override
-    public void setLandscape(boolean landscape) {
+    public void setVertical(boolean vertical) {
         //no op
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java
index 58e6838..7854c98 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java
@@ -106,11 +106,6 @@
      */
     public int location;
 
-    /**
-     * Whether a child in a group is being clipped at the bottom.
-     */
-    public boolean isBottomClipped;
-
     @Override
     public void copyFrom(ViewState viewState) {
         super.copyFrom(viewState);
@@ -125,7 +120,6 @@
             clipTopAmount = svs.clipTopAmount;
             notGoneIndex = svs.notGoneIndex;
             location = svs.location;
-            isBottomClipped = svs.isBottomClipped;
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index 26e1342..b8f8cb2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -76,6 +76,7 @@
     private NotificationViewWrapper mNotificationHeaderWrapper;
     private NotificationHeaderUtil mHeaderUtil;
     private ViewState mHeaderViewState;
+    private int mClipBottomAmount;
 
     public NotificationChildrenContainer(Context context) {
         this(context, null);
@@ -433,7 +434,6 @@
 
         boolean childrenExpanded = !mNotificationParent.isGroupExpansionChanging()
                 && mChildrenExpanded;
-        int parentHeight = parentState.height;
         for (int i = 0; i < childCount; i++) {
             ExpandableNotificationRow child = mChildren.get(i);
             if (!firstChild) {
@@ -457,20 +457,9 @@
 
             ExpandableViewState childState = resultState.getViewStateForView(child);
             int intrinsicHeight = child.getIntrinsicHeight();
-            if (childrenExpanded) {
-                // When a group is expanded and moving into bottom stack, the bottom visible child
-                // adjusts its height to move into it. Children after it are hidden.
-                if (updateChildStateForExpandedGroup(child, parentHeight, childState, yPosition)) {
-                    // Clipping might be deactivated if the view is transforming, however, clipping
-                    // the child into the bottom stack should take precedent over this.
-                    childState.isBottomClipped = true;
-                }
-            } else {
-                childState.hidden = false;
-                childState.height = intrinsicHeight;
-                childState.isBottomClipped = false;
-            }
+            childState.height = intrinsicHeight;
             childState.yTranslation = yPosition;
+            childState.hidden = false;
             // When the group is expanded, the children cast the shadows rather than the parent
             // so use the parent's elevation here.
             childState.zTranslation = childrenExpanded
@@ -601,6 +590,34 @@
         if (mHeaderViewState != null) {
             mHeaderViewState.applyToView(mNotificationHeader);
         }
+        updateChildrenClipping();
+    }
+
+    private void updateChildrenClipping() {
+        int childCount = mChildren.size();
+        int layoutEnd = mNotificationParent.getActualHeight() - mClipBottomAmount;
+        for (int i = 0; i < childCount; i++) {
+            ExpandableNotificationRow child = mChildren.get(i);
+            if (child.getVisibility() == GONE) {
+                continue;
+            }
+            float childTop = child.getTranslationY();
+            float childBottom = childTop + child.getActualHeight();
+            boolean visible = true;
+            int clipBottomAmount = 0;
+            if (childTop > layoutEnd) {
+                visible = false;
+            } else if (childBottom > layoutEnd) {
+                clipBottomAmount = (int) (childBottom - layoutEnd);
+            }
+
+            boolean isVisible = child.getVisibility() == VISIBLE;
+            if (visible != isVisible) {
+                child.setVisibility(visible ? VISIBLE : INVISIBLE);
+            }
+
+            child.setClipBottomAmount(clipBottomAmount);
+        }
     }
 
     /**
@@ -653,6 +670,7 @@
         if (mNotificationHeader != null) {
             mHeaderViewState.applyToView(mNotificationHeader);
         }
+        updateChildrenClipping();
     }
 
     public ExpandableNotificationRow getViewAtPosition(float y) {
@@ -889,4 +907,9 @@
             }
         }
     }
+
+    public void setClipBottomAmount(int clipBottomAmount) {
+        mClipBottomAmount = clipBottomAmount;
+        updateChildrenClipping();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 49da793..10d995c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -766,12 +766,14 @@
      */
     private float getAppearEndPosition() {
         int appearPosition;
+        int minNotificationsForShelf = 1;
         if (mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp()) {
             appearPosition = mHeadsUpManager.getTopHeadsUpPinnedHeight();
+            minNotificationsForShelf = 2;
         } else {
-            appearPosition = getFirstItemMinHeight();
+            appearPosition = 0;
         }
-        if (getNotGoneChildCount() > 1) {
+        if (getNotGoneChildCount() >= minNotificationsForShelf) {
             appearPosition += mShelf.getIntrinsicHeight();
         }
         return appearPosition + (onKeyguard() ? mTopPadding : mIntrinsicPadding);
@@ -1092,29 +1094,7 @@
 
     @Override
     public int getMaxExpandHeight(ExpandableView view) {
-        int maxContentHeight = view.getMaxContentHeight();
-        if (view.isSummaryWithChildren() && view.getParent() == this) {
-            // Faking a measure with the group expanded to simulate how the group would look if
-            // it was. Doing a calculation here would be highly non-trivial because of the
-            // algorithm
-            mGroupExpandedForMeasure = true;
-            ExpandableNotificationRow row = (ExpandableNotificationRow) view;
-            mGroupManager.toggleGroupExpansion(row.getStatusBarNotification());
-            row.setForceUnlocked(true);
-            mAmbientState.setLayoutHeight(mMaxLayoutHeight);
-            mStackScrollAlgorithm.getStackScrollState(mAmbientState, mCurrentStackScrollState);
-            mAmbientState.setLayoutHeight(getLayoutHeight());
-            mGroupManager.toggleGroupExpansion(
-                    row.getStatusBarNotification());
-            mGroupExpandedForMeasure = false;
-            row.setForceUnlocked(false);
-            ExpandableViewState viewState = mCurrentStackScrollState.getViewStateForView(view);
-            if (viewState != null) {
-                // The view could have been removed
-                return Math.min(viewState.height, maxContentHeight);
-            }
-        }
-        return maxContentHeight;
+        return view.getMaxContentHeight();
     }
 
     public void setScrollingEnabled(boolean enable) {
@@ -2126,7 +2106,7 @@
                 finalTranslationY = (int) ViewState.getFinalTranslationY(lastView);
             }
             int finalHeight = ExpandableViewState.getFinalActualHeight(lastView);
-            int finalBottom = finalTranslationY + finalHeight;
+            int finalBottom = finalTranslationY + finalHeight - lastView.getClipBottomAmount();
             finalBottom = Math.min(finalBottom, getHeight());
             if (mAnimateNextBackgroundBottom
                     || mBottomAnimator == null && mCurrentBounds.bottom == finalBottom
@@ -2134,10 +2114,10 @@
                 // we're ending up at the same location as we are now, lets just skip the animation
                 bottom = finalBottom;
             } else {
-                bottom = (int) (lastView.getTranslationY() + lastView.getActualHeight());
+                bottom = (int) (lastView.getTranslationY() + lastView.getActualHeight()
+                        - lastView.getClipBottomAmount());
                 bottom = Math.min(bottom, getHeight());
             }
-            bottom -= lastView.getClipBottomAmount();
         } else {
             top = mTopPadding;
             bottom = top;
@@ -3961,12 +3941,12 @@
     }
 
     public void setShelf(NotificationShelf shelf) {
-        mShelf = shelf;
         int index = -1;
         if (mShelf != null) {
             index = indexOfChild(mShelf);
             removeView(mShelf);
         }
+        mShelf = shelf;
         addView(mShelf, index);
         mAmbientState.setShelf(shelf);
         mStateAnimator.setShelf(shelf);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 1dc346d..7afc7ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -140,7 +140,7 @@
             float newNotificationEnd = newYTranslation + newHeight;
             boolean isHeadsUp = (child instanceof ExpandableNotificationRow)
                     && ((ExpandableNotificationRow) child).isPinned();
-            if (newYTranslation < previousNotificationEnd
+            if (!state.inShelf && newYTranslation < previousNotificationEnd
                     && (!isHeadsUp || ambientState.isShadeExpanded())) {
                 // The previous view is overlapping on top, clip!
                 float overlapAmount = previousNotificationEnd - newYTranslation;
@@ -323,9 +323,6 @@
         int childHeight = getMaxAllowedChildHeight(child);
         childViewState.yTranslation = currentYPosition;
         boolean isDismissView = child instanceof DismissView;
-        if (i == 0) {
-            updateFirstChildHeight(child, childViewState, childHeight, algorithmState, ambientState);
-        }
 
         childViewState.location = ExpandableViewState.LOCATION_MAIN_AREA;
         if (isDismissView) {
@@ -450,29 +447,6 @@
     }
 
     /**
-     * Update the height of the first child i.e clamp it to the bottom stack
-     * @param child the child to update
-     * @param childViewState the viewstate of the child
-     * @param childHeight the height of the child
-     * @param algorithmState the algorithm state
-     * @param ambientState The ambient state of the algorithm
-     */
-    protected void updateFirstChildHeight(ExpandableView child, ExpandableViewState childViewState,
-            int childHeight, StackScrollAlgorithmState algorithmState,
-            AmbientState ambientState) {
-
-        int bottomStart= ambientState.getInnerHeight();
-        if (algorithmState.visibleChildren.size() > 1) {
-            bottomStart -= ambientState.getShelf().getIntrinsicHeight()
-                    - mPaddingBetweenElements;
-        }
-        bottomStart += ambientState.getScrollY();
-            // Collapse and expand the first child while the shade is being expanded
-        childViewState.height = (int) Math.max(Math.min(bottomStart, (float) childHeight),
-                    child.getCollapsedHeight());
-    }
-
-    /**
      * Calculate the Z positions for all children based on the number of items in both stacks and
      * save it in the resultState
      *  @param resultState The result state to update the zTranslation values
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
index 5393d60..bb5632b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
@@ -120,7 +120,26 @@
         mObserver = new SettingObserver(mWorker);
         mObserver.init();
         mReceiver.init();
-        mStreamTitles = mContext.getResources().getStringArray(R.array.volume_stream_titles);
+        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();
     }
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 6e17cf4..b03189c 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -26,6 +26,7 @@
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
     <uses-permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE" />
+    <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
new file mode 100644
index 0000000..639c8da
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.app.admin.DevicePolicyManager;
+import android.app.trust.TrustManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.Looper;
+import android.support.test.runner.AndroidJUnit4;
+import android.telephony.SubscriptionManager;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KeyguardIndicationControllerTest extends SysuiTestCase {
+
+    private final String ORGANIZATION_NAME = "organization";
+    private final String DISCLOSURE_WITH_ORGANIZATION_NAME = "managed by organization";
+
+    private Context mContext = mock(Context.class);
+    private DevicePolicyManager mDevicePolicyManager = mock(DevicePolicyManager.class);
+    private ViewGroup mIndicationArea = mock(ViewGroup.class);
+    private KeyguardIndicationTextView mDisclosure = mock(KeyguardIndicationTextView.class);
+
+    private KeyguardIndicationController mController;
+
+    @Before
+    public void setUp() throws Exception {
+        final Resources resources = mock(Resources.class);
+        when(mContext.getResources()).thenReturn(resources);
+        when(mContext.getContentResolver()).thenReturn(mock(ContentResolver.class));
+        when(mContext.getPackageManager()).thenReturn(mock(PackageManager.class));
+        when(mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)).thenReturn(
+                mock(SubscriptionManager.class));
+        when(mContext.getSystemService(Context.TRUST_SERVICE)).thenReturn(
+                mock(TrustManager.class));
+        when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(
+                mDevicePolicyManager);
+
+        when(resources.getString(R.string.do_disclosure_with_name, ORGANIZATION_NAME))
+                .thenReturn(DISCLOSURE_WITH_ORGANIZATION_NAME);
+
+        when(mIndicationArea.findViewById(R.id.keyguard_indication_enterprise_disclosure))
+                .thenReturn(mDisclosure);
+    }
+
+    private void createController() {
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+        mController = new KeyguardIndicationController(mContext, mIndicationArea, null);
+    }
+
+    @Test
+    public void unmanaged() {
+        when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
+        createController();
+
+        verify(mDisclosure).setVisibility(View.GONE);
+        verifyNoMoreInteractions(mDisclosure);
+    }
+
+    @Test
+    public void managedNoOwnerName() {
+        when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
+        when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
+        createController();
+
+        verify(mDisclosure).setVisibility(View.VISIBLE);
+        verify(mDisclosure).switchIndication(R.string.do_disclosure_generic);
+        verifyNoMoreInteractions(mDisclosure);
+    }
+
+    @Test
+    public void managedOwnerName() {
+        when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
+        when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(ORGANIZATION_NAME);
+        createController();
+
+        verify(mDisclosure).setVisibility(View.VISIBLE);
+        verify(mDisclosure).switchIndication(DISCLOSURE_WITH_ORGANIZATION_NAME);
+        verifyNoMoreInteractions(mDisclosure);
+    }
+
+    @Test
+    public void updateOnTheFly() {
+        when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
+        createController();
+
+        final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
+        reset(mDisclosure);
+
+        when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
+        when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
+        monitor.onKeyguardVisibilityChanged(true);
+
+        verify(mDisclosure).setVisibility(View.VISIBLE);
+        verify(mDisclosure).switchIndication(R.string.do_disclosure_generic);
+        verifyNoMoreInteractions(mDisclosure);
+        reset(mDisclosure);
+
+        when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
+        when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(ORGANIZATION_NAME);
+        monitor.onKeyguardVisibilityChanged(false);
+        monitor.onKeyguardVisibilityChanged(true);
+
+        verify(mDisclosure).setVisibility(View.VISIBLE);
+        verify(mDisclosure).switchIndication(DISCLOSURE_WITH_ORGANIZATION_NAME);
+        verifyNoMoreInteractions(mDisclosure);
+        reset(mDisclosure);
+
+        when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
+        monitor.onKeyguardVisibilityChanged(false);
+        monitor.onKeyguardVisibilityChanged(true);
+
+        verify(mDisclosure).setVisibility(View.GONE);
+        verifyNoMoreInteractions(mDisclosure);
+    }
+}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index fc8c675..f08408b 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2232,6 +2232,14 @@
 
     // ---- End N-MR1 Constants, all N-MR1 constants go above this line ----
 
+    // ACTION: The lockscreen gets shown because the SIM card was removed
+    // SUBTYPE: false: device was previously unlocked, true: device was previously locked
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N-MR2
+    ACTION_LOCK_BECAUSE_SIM_REMOVED = 496;
+
+    // ---- End N-MR2 Constants, all N-MR2 constants go above this line ----
+
     // ------- Begin N Keyboard Shortcuts Helper -----
     // Keyboard Shortcuts Helper is opened/closed.
     KEYBOARD_SHORTCUTS_HELPER = 500;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index ab111a0..df71ced 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -2843,15 +2843,8 @@
                     }
                     if (mMotionEventInjector != null) {
                         List<GestureDescription.GestureStep> steps = gestureSteps.getList();
-                        List<MotionEvent> events = GestureDescription.MotionEventGenerator
-                                .getMotionEventsFromGestureSteps(steps);
-                        // Confirm that the motion events end with an UP event.
-                        if (events.get(events.size() - 1).getAction() == MotionEvent.ACTION_UP) {
-                            mMotionEventInjector.injectEvents(events, mServiceInterface, sequence);
-                            return;
-                        } else {
-                            Slog.e(LOG_TAG, "Gesture is not well-formed");
-                        }
+                         mMotionEventInjector.injectEvents(steps, mServiceInterface, sequence);
+                         return;
                     } else {
                         Slog.e(LOG_TAG, "MotionEventInjector installation timed out");
                     }
diff --git a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
index 8042ddb..48041ad 100644
--- a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
+++ b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
@@ -16,49 +16,67 @@
 
 package com.android.server.accessibility;
 
+import android.accessibilityservice.GestureDescription;
+import android.accessibilityservice.GestureDescription.GestureStep;
+import android.accessibilityservice.GestureDescription.TouchPoint;
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.util.IntArray;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseIntArray;
 import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.WindowManagerPolicy;
 import android.view.accessibility.AccessibilityEvent;
 import com.android.internal.os.SomeArgs;
-import com.android.server.accessibility.AccessibilityManagerService.Service;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
  * Injects MotionEvents to permit {@code AccessibilityService}s to touch the screen on behalf of
  * users.
- *
+ * <p>
  * All methods except {@code injectEvents} must be called only from the main thread.
  */
 public class MotionEventInjector implements EventStreamTransformation, Handler.Callback {
     private static final String LOG_TAG = "MotionEventInjector";
     private static final int MESSAGE_SEND_MOTION_EVENT = 1;
     private static final int MESSAGE_INJECT_EVENTS = 2;
-    private static final int MAX_POINTERS = 11; // Non-binding maximum
+
+    /**
+     * Constants used to initialize all MotionEvents
+     */
+    private static final int EVENT_META_STATE = 0;
+    private static final int EVENT_BUTTON_STATE = 0;
+    private static final int EVENT_DEVICE_ID = 0;
+    private static final int EVENT_EDGE_FLAGS = 0;
+    private static final int EVENT_SOURCE = InputDevice.SOURCE_TOUCHSCREEN;
+    private static final int EVENT_FLAGS = 0;
+    private static final float EVENT_X_PRECISION = 1;
+    private static final float EVENT_Y_PRECISION = 1;
+
+    private static MotionEvent.PointerCoords[] sPointerCoords;
+    private static MotionEvent.PointerProperties[] sPointerProps;
 
     private final Handler mHandler;
     private final SparseArray<Boolean> mOpenGesturesInProgress = new SparseArray<>();
 
-    // These two arrays must be the same length
-    private MotionEvent.PointerProperties[] mPointerProperties =
-            new MotionEvent.PointerProperties[MAX_POINTERS];
-    private MotionEvent.PointerCoords[] mPointerCoords =
-            new MotionEvent.PointerCoords[MAX_POINTERS];
     private EventStreamTransformation mNext;
     private IAccessibilityServiceClient mServiceInterfaceForCurrentGesture;
-    private int mSequenceForCurrentGesture;
-    private int mSourceOfInjectedGesture = InputDevice.SOURCE_UNKNOWN;
+    private IntArray mSequencesInProgress = new IntArray(5);
     private boolean mIsDestroyed = false;
+    private TouchPoint[] mLastTouchPoints;
+    private int mNumLastTouchPoints;
+    private long mDownTime;
+    private long mLastScheduledEventTime;
+    private SparseIntArray mStrokeIdToPointerId = new SparseIntArray(5);
 
     /**
      * @param looper A looper on the main thread to use for dispatching new events
@@ -75,18 +93,18 @@
     }
 
     /**
-     * Schedule a series of events for injection. These events must comprise a complete, valid
-     * sequence. All gestures currently in progress will be cancelled, and all {@code downTime}
-     * and {@code eventTime} fields will be offset by the current time.
+     * Schedule a gesture for injection. The gesture is defined by a set of {@code GestureStep}s,
+     * from which {@code MotionEvent}s will be derived. All gestures currently in progress will be
+     * cancelled.
      *
-     * @param events The events to inject. Must all be from the same source.
+     * @param gestureSteps The gesture steps to inject.
      * @param serviceInterface The interface to call back with a result when the gesture is
      * either complete or cancelled.
      */
-    public void injectEvents(List<MotionEvent> events,
+    public void injectEvents(List<GestureStep> gestureSteps,
             IAccessibilityServiceClient serviceInterface, int sequence) {
         SomeArgs args = SomeArgs.obtain();
-        args.arg1 = events;
+        args.arg1 = gestureSteps;
         args.arg2 = serviceInterface;
         args.argi1 = sequence;
         mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_INJECT_EVENTS, args));
@@ -138,7 +156,7 @@
     public boolean handleMessage(Message message) {
         if (message.what == MESSAGE_INJECT_EVENTS) {
             SomeArgs args = (SomeArgs) message.obj;
-            injectEventsMainThread((List<MotionEvent>) args.arg1,
+            injectEventsMainThread((List<GestureStep>) args.arg1,
                     (IAccessibilityServiceClient) args.arg2, args.argi1);
             args.recycle();
             return true;
@@ -148,16 +166,16 @@
             return false;
         }
         MotionEvent motionEvent = (MotionEvent) message.obj;
-        sendMotionEventToNext(motionEvent, motionEvent,
-                WindowManagerPolicy.FLAG_PASS_TO_USER);
-        // If the message queue is now empty, then this gesture is complete
-        if (!mHandler.hasMessages(MESSAGE_SEND_MOTION_EVENT)) {
-            notifyService(true);
+        sendMotionEventToNext(motionEvent, motionEvent, WindowManagerPolicy.FLAG_PASS_TO_USER);
+        boolean isEndOfSequence = message.arg1 != 0;
+        if (isEndOfSequence) {
+            notifyService(mServiceInterfaceForCurrentGesture, mSequencesInProgress.get(0), true);
+            mSequencesInProgress.remove(0);
         }
         return true;
     }
 
-    private void injectEventsMainThread(List<MotionEvent> events,
+    private void injectEventsMainThread(List<GestureStep> gestureSteps,
             IAccessibilityServiceClient serviceInterface, int sequence) {
         if (mIsDestroyed) {
             try {
@@ -168,48 +186,110 @@
             }
             return;
         }
-        cancelAnyPendingInjectedEvents();
-        mSourceOfInjectedGesture = events.get(0).getSource();
-        cancelAnyGestureInProgress(mSourceOfInjectedGesture);
-        mServiceInterfaceForCurrentGesture = serviceInterface;
-        mSequenceForCurrentGesture = sequence;
+
         if (mNext == null) {
-            notifyService(false);
+            notifyService(serviceInterface, sequence, false);
             return;
         }
 
-        long startTime = SystemClock.uptimeMillis();
+        boolean continuingGesture = newGestureTriesToContinueOldOne(gestureSteps);
+
+        if (continuingGesture) {
+            if ((serviceInterface != mServiceInterfaceForCurrentGesture)
+                    || !prepareToContinueOldGesture(gestureSteps)) {
+                cancelAnyPendingInjectedEvents();
+                notifyService(serviceInterface, sequence, false);
+                return;
+            }
+        }
+        if (!continuingGesture) {
+            cancelAnyPendingInjectedEvents();
+            // Injected gestures have been canceled, but real gestures still need cancelling
+            cancelAnyGestureInProgress(EVENT_SOURCE);
+        }
+        mServiceInterfaceForCurrentGesture = serviceInterface;
+
+        long currentTime = SystemClock.uptimeMillis();
+        List<MotionEvent> events = getMotionEventsFromGestureSteps(gestureSteps,
+                (mSequencesInProgress.size() == 0) ? currentTime : mLastScheduledEventTime);
+        if (events.isEmpty()) {
+            notifyService(serviceInterface, sequence, false);
+            return;
+        }
+        mSequencesInProgress.add(sequence);
+
         for (int i = 0; i < events.size(); i++) {
             MotionEvent event = events.get(i);
-            int numPointers = event.getPointerCount();
-            if (numPointers > mPointerCoords.length) {
-                mPointerCoords = new MotionEvent.PointerCoords[numPointers];
-                mPointerProperties = new MotionEvent.PointerProperties[numPointers];
-            }
-            for (int j = 0; j < numPointers; j++) {
-                if (mPointerCoords[j] == null) {
-                    mPointerCoords[j] = new MotionEvent.PointerCoords();
-                    mPointerProperties[j] = new MotionEvent.PointerProperties();
-                }
-                event.getPointerCoords(j, mPointerCoords[j]);
-                event.getPointerProperties(j, mPointerProperties[j]);
-            }
-
-            /*
-             * MotionEvent doesn't have a setEventTime() method (it carries around history data,
-             * which could become inconsistent), so we need to obtain a new one.
-             */
-            MotionEvent offsetEvent = MotionEvent.obtain(startTime + event.getDownTime(),
-                    startTime + event.getEventTime(), event.getAction(), numPointers,
-                    mPointerProperties, mPointerCoords, event.getMetaState(),
-                    event.getButtonState(), event.getXPrecision(), event.getYPrecision(),
-                    event.getDeviceId(), event.getEdgeFlags(), event.getSource(),
-                    event.getFlags());
-            Message message = mHandler.obtainMessage(MESSAGE_SEND_MOTION_EVENT, offsetEvent);
-            mHandler.sendMessageDelayed(message, event.getEventTime());
+            int isEndOfSequence = (i == events.size() - 1) ? 1 : 0;
+            Message message = mHandler.obtainMessage(
+                    MESSAGE_SEND_MOTION_EVENT, isEndOfSequence, 0, event);
+            mLastScheduledEventTime = event.getEventTime();
+            mHandler.sendMessageDelayed(message, Math.max(0, event.getEventTime() - currentTime));
         }
     }
 
+    private boolean newGestureTriesToContinueOldOne(List<GestureStep> gestureSteps) {
+        if (gestureSteps.isEmpty()) {
+            return false;
+        }
+        GestureStep firstStep = gestureSteps.get(0);
+        for (int i = 0; i < firstStep.numTouchPoints; i++) {
+            if (!firstStep.touchPoints[i].mIsStartOfPath) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * A gesture can only continue a gesture if it contains intermediate points that continue
+     * each continued stroke of the last gesture, and no extra points.
+     *
+     * @param gestureSteps The steps of the new gesture
+     * @return {@code true} if the new gesture could continue the last one dispatched. {@code false}
+     * otherwise.
+     */
+    private boolean prepareToContinueOldGesture(List<GestureStep> gestureSteps) {
+        if (gestureSteps.isEmpty() || (mLastTouchPoints == null) || (mNumLastTouchPoints == 0)) {
+            return false;
+        }
+        GestureStep firstStep = gestureSteps.get(0);
+        // Make sure all of the continuing paths match up
+        int numContinuedStrokes = 0;
+        for (int i = 0; i < firstStep.numTouchPoints; i++) {
+            TouchPoint touchPoint = firstStep.touchPoints[i];
+            if (!touchPoint.mIsStartOfPath) {
+                int continuedPointerId = mStrokeIdToPointerId
+                        .get(touchPoint.mContinuedStrokeId, -1);
+                if (continuedPointerId == -1) {
+                    return false;
+                }
+                mStrokeIdToPointerId.put(touchPoint.mStrokeId, continuedPointerId);
+                int lastPointIndex = findPointByStrokeId(
+                        mLastTouchPoints, mNumLastTouchPoints, touchPoint.mContinuedStrokeId);
+                if (lastPointIndex < 0) {
+                    return false;
+                }
+                if (mLastTouchPoints[lastPointIndex].mIsEndOfPath
+                        || (mLastTouchPoints[lastPointIndex].mX != touchPoint.mX)
+                        || (mLastTouchPoints[lastPointIndex].mY != touchPoint.mY)) {
+                    return false;
+                }
+                // Update the last touch point to match the continuation, so the gestures will
+                // line up
+                mLastTouchPoints[lastPointIndex].mStrokeId = touchPoint.mStrokeId;
+            }
+            numContinuedStrokes++;
+        }
+        // Make sure we didn't miss any paths
+        for (int i = 0; i < mNumLastTouchPoints; i++) {
+            if (!mLastTouchPoints[i].mIsEndOfPath) {
+                numContinuedStrokes--;
+            }
+        }
+        return numContinuedStrokes == 0;
+    }
+
     private void sendMotionEventToNext(MotionEvent event, MotionEvent rawEvent,
             int policyFlags) {
         if (mNext != null) {
@@ -228,7 +308,7 @@
         if ((mNext != null) && mOpenGesturesInProgress.get(source, false)) {
             long now = SystemClock.uptimeMillis();
             MotionEvent cancelEvent =
-                    MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
+                    obtainMotionEvent(now, now, MotionEvent.ACTION_CANCEL, getLastTouchPoints(), 1);
             sendMotionEventToNext(cancelEvent, cancelEvent,
                     WindowManagerPolicy.FLAG_PASS_TO_USER);
             mOpenGesturesInProgress.put(source, false);
@@ -237,19 +317,187 @@
 
     private void cancelAnyPendingInjectedEvents() {
         if (mHandler.hasMessages(MESSAGE_SEND_MOTION_EVENT)) {
-            cancelAnyGestureInProgress(mSourceOfInjectedGesture);
             mHandler.removeMessages(MESSAGE_SEND_MOTION_EVENT);
-            notifyService(false);
+            cancelAnyGestureInProgress(EVENT_SOURCE);
+            for (int i = mSequencesInProgress.size() - 1; i >= 0; i--) {
+                notifyService(mServiceInterfaceForCurrentGesture,
+                        mSequencesInProgress.get(i), false);
+                mSequencesInProgress.remove(i);
+            }
+        } else if (mNumLastTouchPoints != 0) {
+            // An injected gesture is in progress and waiting for a continuation. Cancel it.
+            cancelAnyGestureInProgress(EVENT_SOURCE);
         }
+        mNumLastTouchPoints = 0;
+        mStrokeIdToPointerId.clear();
     }
 
-    private void notifyService(boolean success) {
+    private void notifyService(IAccessibilityServiceClient service, int sequence, boolean success) {
         try {
-            mServiceInterfaceForCurrentGesture.onPerformGestureResult(
-                    mSequenceForCurrentGesture, success);
+            service.onPerformGestureResult(sequence, success);
         } catch (RemoteException re) {
             Slog.e(LOG_TAG, "Error sending motion event injection status to "
                     + mServiceInterfaceForCurrentGesture, re);
         }
     }
+
+    private List<MotionEvent> getMotionEventsFromGestureSteps(
+            List<GestureStep> steps, long startTime) {
+        final List<MotionEvent> motionEvents = new ArrayList<>();
+
+        TouchPoint[] lastTouchPoints = getLastTouchPoints();
+
+        for (int i = 0; i < steps.size(); i++) {
+            GestureDescription.GestureStep step = steps.get(i);
+            int currentTouchPointSize = step.numTouchPoints;
+            if (currentTouchPointSize > lastTouchPoints.length) {
+                mNumLastTouchPoints = 0;
+                motionEvents.clear();
+                return motionEvents;
+            }
+
+            appendMoveEventIfNeeded(motionEvents, step.touchPoints, currentTouchPointSize,
+                    startTime + step.timeSinceGestureStart);
+            appendUpEvents(motionEvents, step.touchPoints, currentTouchPointSize,
+                    startTime + step.timeSinceGestureStart);
+            appendDownEvents(motionEvents, step.touchPoints, currentTouchPointSize,
+                    startTime + step.timeSinceGestureStart);
+        }
+        return motionEvents;
+    }
+
+    private TouchPoint[] getLastTouchPoints() {
+        if (mLastTouchPoints == null) {
+            int capacity = GestureDescription.getMaxStrokeCount();
+            mLastTouchPoints = new TouchPoint[capacity];
+            for (int i = 0; i < capacity; i++) {
+                mLastTouchPoints[i] = new GestureDescription.TouchPoint();
+            }
+        }
+        return mLastTouchPoints;
+    }
+
+    private void appendMoveEventIfNeeded(List<MotionEvent> motionEvents,
+            TouchPoint[] currentTouchPoints, int currentTouchPointsSize, long currentTime) {
+            /* Look for pointers that have moved */
+        boolean moveFound = false;
+        TouchPoint[] lastTouchPoints = getLastTouchPoints();
+        for (int i = 0; i < currentTouchPointsSize; i++) {
+            int lastPointsIndex = findPointByStrokeId(lastTouchPoints, mNumLastTouchPoints,
+                    currentTouchPoints[i].mStrokeId);
+            if (lastPointsIndex >= 0) {
+                moveFound |= (lastTouchPoints[lastPointsIndex].mX != currentTouchPoints[i].mX)
+                        || (lastTouchPoints[lastPointsIndex].mY != currentTouchPoints[i].mY);
+                lastTouchPoints[lastPointsIndex].copyFrom(currentTouchPoints[i]);
+            }
+        }
+
+        if (moveFound) {
+            motionEvents.add(obtainMotionEvent(mDownTime, currentTime, MotionEvent.ACTION_MOVE,
+                    lastTouchPoints, mNumLastTouchPoints));
+        }
+    }
+
+    private void appendUpEvents(List<MotionEvent> motionEvents,
+            TouchPoint[] currentTouchPoints, int currentTouchPointsSize, long currentTime) {
+        /* Look for a pointer at the end of its path */
+        TouchPoint[] lastTouchPoints = getLastTouchPoints();
+        for (int i = 0; i < currentTouchPointsSize; i++) {
+            if (currentTouchPoints[i].mIsEndOfPath) {
+                int indexOfUpEvent = findPointByStrokeId(lastTouchPoints, mNumLastTouchPoints,
+                        currentTouchPoints[i].mStrokeId);
+                if (indexOfUpEvent < 0) {
+                    continue; // Should not happen
+                }
+                int action = (mNumLastTouchPoints == 1) ? MotionEvent.ACTION_UP
+                        : MotionEvent.ACTION_POINTER_UP;
+                action |= indexOfUpEvent << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+                motionEvents.add(obtainMotionEvent(mDownTime, currentTime, action,
+                        lastTouchPoints, mNumLastTouchPoints));
+                    /* Remove this point from lastTouchPoints */
+                for (int j = indexOfUpEvent; j < mNumLastTouchPoints - 1; j++) {
+                    lastTouchPoints[j].copyFrom(mLastTouchPoints[j + 1]);
+                }
+                mNumLastTouchPoints--;
+                if (mNumLastTouchPoints == 0) {
+                    mStrokeIdToPointerId.clear();
+                }
+            }
+        }
+    }
+
+    private void appendDownEvents(List<MotionEvent> motionEvents,
+            TouchPoint[] currentTouchPoints, int currentTouchPointsSize, long currentTime) {
+        /* Look for a pointer that is just starting */
+        TouchPoint[] lastTouchPoints = getLastTouchPoints();
+        for (int i = 0; i < currentTouchPointsSize; i++) {
+            if (currentTouchPoints[i].mIsStartOfPath) {
+                /* Add the point to last coords and use the new array to generate the event */
+                lastTouchPoints[mNumLastTouchPoints++].copyFrom(currentTouchPoints[i]);
+                int action = (mNumLastTouchPoints == 1) ? MotionEvent.ACTION_DOWN
+                        : MotionEvent.ACTION_POINTER_DOWN;
+                if (action == MotionEvent.ACTION_DOWN) {
+                    mDownTime = currentTime;
+                }
+                action |= i << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+                motionEvents.add(obtainMotionEvent(mDownTime, currentTime, action,
+                        lastTouchPoints, mNumLastTouchPoints));
+            }
+        }
+    }
+
+    private MotionEvent obtainMotionEvent(long downTime, long eventTime, int action,
+            TouchPoint[] touchPoints, int touchPointsSize) {
+        if ((sPointerCoords == null) || (sPointerCoords.length < touchPointsSize)) {
+            sPointerCoords = new MotionEvent.PointerCoords[touchPointsSize];
+            for (int i = 0; i < touchPointsSize; i++) {
+                sPointerCoords[i] = new MotionEvent.PointerCoords();
+            }
+        }
+        if ((sPointerProps == null) || (sPointerProps.length < touchPointsSize)) {
+            sPointerProps = new MotionEvent.PointerProperties[touchPointsSize];
+            for (int i = 0; i < touchPointsSize; i++) {
+                sPointerProps[i] = new MotionEvent.PointerProperties();
+            }
+        }
+        for (int i = 0; i < touchPointsSize; i++) {
+            int pointerId = mStrokeIdToPointerId.get(touchPoints[i].mStrokeId, -1);
+            if (pointerId == -1) {
+                pointerId = getUnusedPointerId();
+                mStrokeIdToPointerId.put(touchPoints[i].mStrokeId, pointerId);
+            }
+            sPointerProps[i].id = pointerId;
+            sPointerProps[i].toolType = MotionEvent.TOOL_TYPE_UNKNOWN;
+            sPointerCoords[i].clear();
+            sPointerCoords[i].pressure = 1.0f;
+            sPointerCoords[i].size = 1.0f;
+            sPointerCoords[i].x = touchPoints[i].mX;
+            sPointerCoords[i].y = touchPoints[i].mY;
+        }
+        return MotionEvent.obtain(downTime, eventTime, action, touchPointsSize,
+                sPointerProps, sPointerCoords, EVENT_META_STATE, EVENT_BUTTON_STATE,
+                EVENT_X_PRECISION, EVENT_Y_PRECISION, EVENT_DEVICE_ID, EVENT_EDGE_FLAGS,
+                EVENT_SOURCE, EVENT_FLAGS);
+    }
+
+    private static int findPointByStrokeId(TouchPoint[] touchPoints, int touchPointsSize,
+            int strokeId) {
+        for (int i = 0; i < touchPointsSize; i++) {
+            if (touchPoints[i].mStrokeId == strokeId) {
+                return i;
+            }
+        }
+        return -1;
+    }
+    private int getUnusedPointerId() {
+        int MAX_POINTER_ID = 10;
+        int pointerId = 0;
+        while (mStrokeIdToPointerId.indexOfValue(pointerId) >= 0) {
+            pointerId++;
+            if (pointerId >= MAX_POINTER_ID) {
+                return MAX_POINTER_ID;
+            }
+        }
+        return pointerId;
+    }
 }
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 8151c8a..31ecb75 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -2399,16 +2399,15 @@
                         } catch (InterruptedException e) {
                             // just bail
                             Slog.w(TAG, "Interrupted: " + e);
-                            mActivityManager.clearPendingBackup();
-                            return null;
+                            mConnecting = false;
+                            mConnectedAgent = null;
                         }
                     }
 
                     // if we timed out with no connect, abort and move on
                     if (mConnecting == true) {
                         Slog.w(TAG, "Timeout waiting for agent " + app);
-                        mActivityManager.clearPendingBackup();
-                        return null;
+                        mConnectedAgent = null;
                     }
                     if (DEBUG) Slog.i(TAG, "got agent " + mConnectedAgent);
                     agent = mConnectedAgent;
@@ -2417,6 +2416,13 @@
                 // can't happen - ActivityManager is local
             }
         }
+        if (agent == null) {
+            try {
+                mActivityManager.clearPendingBackup();
+            } catch (RemoteException e) {
+                // can't happen - ActivityManager is local
+            }
+        }
         return agent;
     }
 
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index f7068cf..b0c5603 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -42,6 +42,7 @@
 import android.database.ContentObserver;
 import android.os.Binder;
 import android.os.Build;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -52,6 +53,8 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.UserManagerInternal;
+import android.os.UserManagerInternal.UserRestrictionsListener;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.util.Slog;
@@ -177,6 +180,24 @@
         }
     };
 
+    private final UserRestrictionsListener mUserRestrictionsListener =
+            new UserRestrictionsListener() {
+        @Override
+        public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
+                Bundle prevRestrictions) {
+            final boolean bluetoothDisallowed =
+                    newRestrictions.getBoolean(UserManager.DISALLOW_BLUETOOTH);
+            if ((mEnable || mEnableExternal) && bluetoothDisallowed) {
+                try {
+                    disable(null, true);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Exception when disabling Bluetooth from UserRestrictionsListener",
+                            e);
+                }
+            }
+        }
+    };
+
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -634,6 +655,13 @@
 
     public boolean enableNoAutoConnect()
     {
+        if (isBluetoothDisallowed()) {
+            if (DBG) {
+                Slog.d(TAG, "enableNoAutoConnect(): not enabling - bluetooth disallowed");
+            }
+            return false;
+        }
+
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                                 "Need BLUETOOTH ADMIN permission");
 
@@ -659,6 +687,13 @@
         final int callingUid = Binder.getCallingUid();
         final boolean callerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID;
 
+        if (isBluetoothDisallowed()) {
+            if (DBG) {
+                Slog.d(TAG,"enable(): not enabling - bluetooth disallowed");
+            }
+            return false;
+        }
+
         if (!callerSystem) {
             if (!checkIfCallerIsForegroundUser()) {
                 Slog.w(TAG, "enable(): not allowed for non-active and non system user");
@@ -872,6 +907,12 @@
      */
     public void handleOnBootPhase() {
         if (DBG) Slog.d(TAG, "Bluetooth boot completed");
+        UserManagerInternal userManagerInternal =
+                LocalServices.getService(UserManagerInternal.class);
+        userManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
+        if (isBluetoothDisallowed()) {
+            return;
+        }
         if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
             if (DBG) Slog.d(TAG, "Auto-enabling Bluetooth.");
             sendEnableMsg(mQuietEnableExternal);
@@ -1916,6 +1957,16 @@
         }
     }
 
+    private boolean isBluetoothDisallowed() {
+        long callingIdentity = Binder.clearCallingIdentity();
+        try {
+            return mContext.getSystemService(UserManager.class)
+                    .hasUserRestriction(UserManager.DISALLOW_BLUETOOTH, UserHandle.SYSTEM);
+        } finally {
+            Binder.restoreCallingIdentity(callingIdentity);
+        }
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 07322fc..8092b4a 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -1430,7 +1430,7 @@
         synchronized (this) {
             try {
                 ApplicationInfo ai = getContext().getPackageManager().getApplicationInfo(name,
-                        PackageManager.MATCH_UNINSTALLED_PACKAGES);
+                        PackageManager.MATCH_ANY_USER);
                 if (mPowerSaveWhitelistUserApps.put(name, UserHandle.getAppId(ai.uid)) == null) {
                     reportPowerSaveWhitelistChangedLocked();
                     updateWhitelistAppIdsLocked();
@@ -2396,7 +2396,7 @@
                     if (name != null) {
                         try {
                             ApplicationInfo ai = pm.getApplicationInfo(name,
-                                    PackageManager.MATCH_UNINSTALLED_PACKAGES);
+                                    PackageManager.MATCH_ANY_USER);
                             mPowerSaveWhitelistUserApps.put(ai.packageName,
                                     UserHandle.getAppId(ai.uid));
                         } catch (PackageManager.NameNotFoundException e) {
diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java
index 0414b47..8402087 100644
--- a/services/core/java/com/android/server/MmsServiceBroker.java
+++ b/services/core/java/com/android/server/MmsServiceBroker.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import android.Manifest;
+import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
 import android.content.ComponentName;
@@ -499,13 +500,21 @@
          */
         private Uri adjustUriForUserAndGrantPermission(Uri contentUri, String action,
                 int permission) {
+            final Intent grantIntent = new Intent();
+            grantIntent.setData(contentUri);
+            grantIntent.setFlags(permission);
+
+            final int callingUid = Binder.getCallingUid();
             final int callingUserId = UserHandle.getCallingUserId();
             if (callingUserId != UserHandle.USER_SYSTEM) {
                 contentUri = ContentProvider.maybeAddUserId(contentUri, callingUserId);
             }
+
             long token = Binder.clearCallingIdentity();
             try {
-                mContext.grantUriPermission(PHONE_PACKAGE_NAME, contentUri, permission);
+                LocalServices.getService(ActivityManagerInternal.class)
+                        .grantUriPermissionFromIntent(callingUid, PHONE_PACKAGE_NAME,
+                                grantIntent, UserHandle.USER_SYSTEM);
 
                 // Grant permission for the carrier app.
                 Intent intent = new Intent(action);
@@ -514,7 +523,9 @@
                 List<String> carrierPackages = telephonyManager.getCarrierPackageNamesForIntent(
                         intent);
                 if (carrierPackages != null && carrierPackages.size() == 1) {
-                    mContext.grantUriPermission(carrierPackages.get(0), contentUri, permission);
+                    LocalServices.getService(ActivityManagerInternal.class)
+                            .grantUriPermissionFromIntent(callingUid, carrierPackages.get(0),
+                                    grantIntent, UserHandle.USER_SYSTEM);
                 }
             } finally {
                 Binder.restoreCallingIdentity(token);
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index f5cda0a..72fa1e3 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -41,6 +41,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.TransferPipe;
 
@@ -63,6 +64,7 @@
     private static final boolean DBG = false;
 
     private final Context mContext;
+    private final NetworkScorerAppManager mNetworkScorerAppManager;
     private final Map<Integer, INetworkScoreCache> mScoreCaches;
     /** Lock used to update mPackageMonitor when scorer package changes occur. */
     private final Object mPackageMonitorLock = new Object[0];
@@ -133,7 +135,7 @@
                             + ", forceUnbind=" + forceUnbind);
                 }
                 final NetworkScorerAppData activeScorer =
-                        NetworkScorerAppManager.getActiveScorer(mContext);
+                        mNetworkScorerAppManager.getActiveScorer();
                 if (activeScorer == null) {
                     // Package change has invalidated a scorer, this will also unbind any service
                     // connection.
@@ -154,7 +156,13 @@
     }
 
     public NetworkScoreService(Context context) {
+      this(context, new NetworkScorerAppManager(context));
+    }
+
+    @VisibleForTesting
+    NetworkScoreService(Context context, NetworkScorerAppManager networkScoreAppManager) {
         mContext = context;
+        mNetworkScorerAppManager = networkScoreAppManager;
         mScoreCaches = new HashMap<>();
         IntentFilter filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
         // TODO: Need to update when we support per-user scorers. http://b/23422763
@@ -173,7 +181,7 @@
             String defaultPackage = mContext.getResources().getString(
                     R.string.config_defaultNetworkScorerPackageName);
             if (!TextUtils.isEmpty(defaultPackage)) {
-                NetworkScorerAppManager.setActiveScorer(mContext, defaultPackage);
+                mNetworkScorerAppManager.setActiveScorer(defaultPackage);
             }
             Settings.Global.putInt(cr, Settings.Global.NETWORK_SCORING_PROVISIONED, 1);
         }
@@ -194,7 +202,7 @@
 
     private void registerPackageMonitorIfNeeded() {
         if (DBG) Log.d(TAG, "registerPackageMonitorIfNeeded");
-        NetworkScorerAppData scorer = NetworkScorerAppManager.getActiveScorer(mContext);
+        NetworkScorerAppData scorer = mNetworkScorerAppManager.getActiveScorer();
         synchronized (mPackageMonitorLock) {
             // Unregister the current monitor if needed.
             if (mPackageMonitor != null) {
@@ -222,7 +230,7 @@
 
     private void bindToScoringServiceIfNeeded() {
         if (DBG) Log.d(TAG, "bindToScoringServiceIfNeeded");
-        NetworkScorerAppData scorerData = NetworkScorerAppManager.getActiveScorer(mContext);
+        NetworkScorerAppData scorerData = mNetworkScorerAppManager.getActiveScorer();
         bindToScoringServiceIfNeeded(scorerData);
     }
 
@@ -259,7 +267,7 @@
 
     @Override
     public boolean updateScores(ScoredNetwork[] networks) {
-        if (!NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid())) {
+        if (!mNetworkScorerAppManager.isCallerActiveScorer(getCallingUid())) {
             throw new SecurityException("Caller with UID " + getCallingUid() +
                     " is not the active scorer.");
         }
@@ -298,7 +306,7 @@
     public boolean clearScores() {
         // Only the active scorer or the system (who can broadcast BROADCAST_NETWORK_PRIVILEGED)
         // should be allowed to flush all scores.
-        if (NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid()) ||
+        if (mNetworkScorerAppManager.isCallerActiveScorer(getCallingUid()) ||
                 mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED) ==
                         PackageManager.PERMISSION_GRANTED) {
             clearInternal();
@@ -328,7 +336,7 @@
     public void disableScoring() {
         // Only the active scorer or the system (who can broadcast BROADCAST_NETWORK_PRIVILEGED)
         // should be allowed to disable scoring.
-        if (NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid()) ||
+        if (mNetworkScorerAppManager.isCallerActiveScorer(getCallingUid()) ||
                 mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED) ==
                         PackageManager.PERMISSION_GRANTED) {
             // The return value is discarded here because at this point, the call should always
@@ -352,8 +360,8 @@
             // only be allowing valid apps to be set as scorers, so failure here should be rare.
             clearInternal();
             // Get the scorer that is about to be replaced, if any, so we can notify it directly.
-            NetworkScorerAppData prevScorer = NetworkScorerAppManager.getActiveScorer(mContext);
-            boolean result = NetworkScorerAppManager.setActiveScorer(mContext, packageName);
+            NetworkScorerAppData prevScorer = mNetworkScorerAppManager.getActiveScorer();
+            boolean result = mNetworkScorerAppManager.setActiveScorer(packageName);
             // Unconditionally attempt to bind to the current scorer. If setActiveScorer() failed
             // then we'll attempt to restore the previous binding (if any), otherwise an attempt
             // will be made to bind to the new scorer.
@@ -411,7 +419,7 @@
     @Override
     protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG);
-        NetworkScorerAppData currentScorer = NetworkScorerAppManager.getActiveScorer(mContext);
+        NetworkScorerAppData currentScorer = mNetworkScorerAppManager.getActiveScorer();
         if (currentScorer == null) {
             writer.println("Scoring is disabled.");
             return;
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index 080b46c..698f1eb 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -26,7 +26,6 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.provider.Settings;
 import android.service.persistentdata.IPersistentDataBlockService;
 import android.service.persistentdata.PersistentDataBlockManager;
 import android.util.Slog;
@@ -53,15 +52,14 @@
  * This data will live across factory resets not initiated via the Settings UI.
  * When a device is factory reset through Settings this data is wiped.
  *
- * Allows writing one block at a time. Namely, each time
- * {@link android.service.persistentdata.IPersistentDataBlockService}.write(byte[] data)
- * is called, it will overwite the data that was previously written on the block.
+ * Allows writing one block at a time. Namely, each time {@link IPersistentDataBlockService#write}
+ * is called, it will overwrite the data that was previously written on the block.
  *
  * Clients can query the size of the currently written block via
- * {@link android.service.persistentdata.IPersistentDataBlockService}.getTotalDataSize().
+ * {@link IPersistentDataBlockService#getDataBlockSize}
  *
- * Clients can any number of bytes from the currently written block up to its total size by invoking
- * {@link android.service.persistentdata.IPersistentDataBlockService}.read(byte[] data)
+ * Clients can read any number of bytes from the currently written block up to its total size by
+ * invoking {@link IPersistentDataBlockService#read}
  */
 public class PersistentDataBlockService extends SystemService {
     private static final String TAG = PersistentDataBlockService.class.getSimpleName();
@@ -84,6 +82,7 @@
 
     private int mAllowedUid = -1;
     private long mBlockDeviceSize;
+    private boolean mIsWritable = true;
 
     public PersistentDataBlockService(Context context) {
         super(context);
@@ -377,6 +376,11 @@
             headerAndData.put(data);
 
             synchronized (mLock) {
+                if (!mIsWritable) {
+                    IoUtils.closeQuietly(outputStream);
+                    return -1;
+                }
+
                 try {
                     byte[] checksum = new byte[DIGEST_SIZE_BYTES];
                     outputStream.write(checksum, 0, DIGEST_SIZE_BYTES);
@@ -451,6 +455,9 @@
 
                 if (ret < 0) {
                     Slog.e(TAG, "failed to wipe persistent partition");
+                } else {
+                    mIsWritable = false;
+                    Slog.i(TAG, "persistent partition now wiped and unwritable");
                 }
             }
         }
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 11fabb4..55d31c3 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -644,14 +644,8 @@
                         Slog.e(TAG, "Unable to record last fstrim!");
                     }
 
-                    final boolean shouldBenchmark = shouldBenchmark();
-                    try {
-                        // This method must be run on the main (handler) thread,
-                        // so it is safe to directly call into vold.
-                        mConnector.execute("fstrim", shouldBenchmark ? "dotrimbench" : "dotrim");
-                    } catch (NativeDaemonConnectorException ndce) {
-                        Slog.e(TAG, "Failed to run fstrim!");
-                    }
+                    final int flags = shouldBenchmark() ? StorageManager.FSTRIM_FLAG_BENCHMARK : 0;
+                    fstrim(flags);
 
                     // invoke the completion callback, if any
                     // TODO: fstrim is non-blocking, so remove this useless callback
@@ -1956,6 +1950,28 @@
         }
     }
 
+    @Override
+    public void fstrim(int flags) {
+        enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
+        waitForReady();
+
+        String cmd;
+        if ((flags & StorageManager.FSTRIM_FLAG_DEEP) != 0) {
+            cmd = "dodtrim";
+        } else {
+            cmd = "dotrim";
+        }
+        if ((flags & StorageManager.FSTRIM_FLAG_BENCHMARK) != 0) {
+            cmd += "bench";
+        }
+
+        try {
+            mConnector.execute("fstrim", cmd);
+        } catch (NativeDaemonConnectorException e) {
+            Slog.e(TAG, "Failed to run fstrim: " + e);
+        }
+    }
+
     private void remountUidExternalStorage(int uid, int mode) {
         waitForReady();
 
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 2932a1a..62f4f19 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1381,7 +1381,6 @@
         }
 
         Intent intent = new Intent(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED);
-        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
         Bundle data = new Bundle();
         signalStrength.fillInNotifierBundle(data);
         intent.putExtras(data);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 136e02c..7661127 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -75,6 +75,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
+import android.webkit.WebViewZygote;
 
 public final class ActiveServices {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActiveServices" : TAG_AM;
@@ -1704,6 +1705,7 @@
 
         final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
         final String procName = r.processName;
+        String hostingType = "service";
         ProcessRecord app;
 
         if (!isolated) {
@@ -1732,13 +1734,17 @@
             // in the service any current isolated process it is running in or
             // waiting to have come up.
             app = r.isolatedProc;
+            if (WebViewZygote.isMultiprocessEnabled()
+                    && r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
+                hostingType = "webview_service";
+            }
         }
 
         // Not running -- get it started, and enqueue this service record
         // to be executed when the app comes up.
         if (app == null && !permissionsReviewRequired) {
             if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
-                    "service", r.name, false, isolated, false)) == null) {
+                    hostingType, r.name, false, isolated, false)) == null) {
                 String msg = "Unable to launch app "
                         + r.appInfo.packageName + "/"
                         + r.appInfo.uid + " for service "
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d085a47..6aa0dc9 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -21,7 +21,6 @@
 import android.app.ContentProviderHolder;
 import android.app.IActivityManager;
 import android.app.WaitResult;
-import android.graphics.PointF;
 import android.os.IDeviceIdentifiersPolicyService;
 
 import com.android.internal.policy.IKeyguardDismissCallback;
@@ -201,6 +200,7 @@
 import android.os.storage.IStorageManager;
 import android.os.storage.StorageManagerInternal;
 import android.os.storage.StorageManager;
+import android.provider.Downloads;
 import android.provider.Settings;
 import android.service.voice.IVoiceInteractionSession;
 import android.service.voice.VoiceInteractionManagerInternal;
@@ -272,10 +272,12 @@
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
 import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
 import static android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY;
 import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
 import static android.content.pm.PackageManager.GET_PROVIDERS;
+import static android.content.pm.PackageManager.MATCH_ANY_USER;
 import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
@@ -361,7 +363,6 @@
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBLE_BEHIND;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.FORCE_NEW_TASK_FLAGS;
 import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
 import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS;
@@ -2881,9 +2882,11 @@
 
     @Override
     public void batterySendBroadcast(Intent intent) {
-        broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
-                AppOpsManager.OP_NONE, null, false, false,
-                -1, Process.SYSTEM_UID, UserHandle.USER_ALL);
+        synchronized (this) {
+            broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
+                    AppOpsManager.OP_NONE, null, false, false,
+                    -1, Process.SYSTEM_UID, UserHandle.USER_ALL);
+        }
     }
 
     /**
@@ -3692,10 +3695,18 @@
             Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                     app.processName);
             checkTime(startTime, "startProcess: asking zygote to start proc");
-            Process.ProcessStartResult startResult = Process.start(entryPoint,
-                    app.processName, uid, uid, gids, debugFlags, mountExternal,
-                    app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
-                    app.info.dataDir, entryPointArgs);
+            Process.ProcessStartResult startResult;
+            if (hostingType.equals("webview_service")) {
+                startResult = Process.startWebView(entryPoint,
+                        app.processName, uid, uid, gids, debugFlags, mountExternal,
+                        app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
+                        app.info.dataDir, 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);
+            }
             checkTime(startTime, "startProcess: returned from zygote!");
             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
 
@@ -8511,6 +8522,12 @@
                     // Only inspect grants matching package
                     if (packageName == null || perm.sourcePkg.equals(packageName)
                             || perm.targetPkg.equals(packageName)) {
+                        // Hacky solution as part of fixing a security bug; ignore
+                        // grants associated with DownloadManager so we don't have
+                        // to immediately launch it to regrant the permissions
+                        if (Downloads.Impl.AUTHORITY.equals(perm.uri.uri.getAuthority())
+                                && !persistable) continue;
+
                         persistChanged |= perm.revokeModes(persistable
                                 ? ~0 : ~Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, true);
 
@@ -9174,10 +9191,10 @@
                         }
                     }
                     final ActivityStack stack = tr.getStack();
-                    if ((flags & ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS) != 0) {
-                        if (stack != null && stack.isHomeStack()) {
+                    if ((flags & ActivityManager.RECENT_IGNORE_HOME_AND_RECENTS_STACK_TASKS) != 0) {
+                        if (stack != null && stack.isHomeOrRecentsStack()) {
                             if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
-                                    "Skipping, home stack task: " + tr);
+                                    "Skipping, home or recents stack task: " + tr);
                             continue;
                         }
                     }
@@ -9599,8 +9616,8 @@
     @Override
     public void removeStack(int stackId) {
         enforceCallingPermission(Manifest.permission.MANAGE_ACTIVITY_STACKS, "removeStack()");
-        if (stackId == HOME_STACK_ID) {
-            throw new IllegalArgumentException("Removing home stack is not allowed.");
+        if (StackId.isHomeOrRecentsStack(stackId)) {
+            throw new IllegalArgumentException("Removing home or recents stack is not allowed.");
         }
 
         synchronized (this) {
@@ -9828,9 +9845,9 @@
     @Override
     public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
         enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToStack()");
-        if (stackId == HOME_STACK_ID) {
+        if (StackId.isHomeOrRecentsStack(stackId)) {
             throw new IllegalArgumentException(
-                    "moveTaskToStack: Attempt to move task " + taskId + " to home stack");
+                    "moveTaskToStack: Attempt to move task " + taskId + " to stack " + stackId);
         }
         synchronized (this) {
             long ident = Binder.clearCallingIdentity();
@@ -9845,8 +9862,7 @@
                         !FORCE_FOCUS, "moveTaskToStack", ANIMATE);
                 if (result && stackId == DOCKED_STACK_ID) {
                     // If task moved to docked stack - show recents if needed.
-                    mStackSupervisor.moveHomeStackTaskToTop(RECENTS_ACTIVITY_TYPE,
-                            "moveTaskToDockedStack");
+                    mWindowManager.showRecentApps(false /* fromHome */);
                 }
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -10030,10 +10046,10 @@
     @Override
     public void positionTaskInStack(int taskId, int stackId, int position) {
         enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "positionTaskInStack()");
-        if (stackId == HOME_STACK_ID) {
+        if (StackId.isHomeOrRecentsStack(stackId)) {
             throw new IllegalArgumentException(
                     "positionTaskInStack: Attempt to change the position of task "
-                    + taskId + " in/to home stack");
+                    + taskId + " in/to home/recents stack");
         }
         synchronized (this) {
             long ident = Binder.clearCallingIdentity();
@@ -10075,22 +10091,6 @@
     }
 
     @Override
-    public boolean isInHomeStack(int taskId) {
-        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
-        long ident = Binder.clearCallingIdentity();
-        try {
-            synchronized (this) {
-                final TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(
-                        taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID);
-                final ActivityStack stack = tr != null ? tr.getStack() : null;
-                return stack != null && stack.isHomeStack();
-            }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    @Override
     public int getTaskForActivity(IBinder token, boolean onlyRoot) {
         synchronized(this) {
             return ActivityRecord.getTaskForActivityLocked(token, onlyRoot);
@@ -14429,7 +14429,7 @@
         if (dumpPackage != null) {
             IPackageManager pm = AppGlobals.getPackageManager();
             try {
-                dumpUid = pm.getPackageUid(dumpPackage, MATCH_UNINSTALLED_PACKAGES, 0);
+                dumpUid = pm.getPackageUid(dumpPackage, MATCH_ANY_USER, 0);
             } catch (RemoteException e) {
             }
         }
@@ -15406,7 +15406,7 @@
             if (dumpPackage != null) {
                 try {
                     dumpUid = mContext.getPackageManager().getPackageUidAsUser(dumpPackage,
-                            MATCH_UNINSTALLED_PACKAGES, 0);
+                            MATCH_ANY_USER, 0);
                 } catch (NameNotFoundException e) {
                     dumpUid = -1;
                 }
@@ -18836,8 +18836,8 @@
     @Override
     public void moveTasksToFullscreenStack(int fromStackId, boolean onTop) {
         enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTasksToFullscreenStack()");
-        if (fromStackId == HOME_STACK_ID) {
-            throw new IllegalArgumentException("You can't move tasks from the home stack.");
+        if (StackId.isHomeOrRecentsStack(fromStackId)) {
+            throw new IllegalArgumentException("You can't move tasks from the home/recents stack.");
         }
         synchronized (this) {
             final long origId = Binder.clearCallingIdentity();
@@ -19114,6 +19114,16 @@
         enforceCallingPermission(CHANGE_CONFIGURATION, "updateDisplayOverrideConfiguration()");
 
         synchronized (this) {
+            // Check if display is initialized in AM.
+            if (!mStackSupervisor.isDisplayAdded(displayId)) {
+                // Call might come when display is not yet added or has already been removed.
+                if (DEBUG_CONFIGURATION) {
+                    Slog.w(TAG, "Trying to update display configuration for non-existing displayId="
+                            + displayId);
+                }
+                return false;
+            }
+
             if (values == null && mWindowManager != null) {
                 // sentinel: fetch the current configuration from the window manager
                 values = mWindowManager.computeNewConfiguration(displayId);
@@ -22129,6 +22139,15 @@
 
     private final class LocalService extends ActivityManagerInternal {
         @Override
+        public void grantUriPermissionFromIntent(int callingUid, String targetPkg, Intent intent,
+                int targetUserId) {
+            synchronized (ActivityManagerService.this) {
+                ActivityManagerService.this.grantUriPermissionFromIntentLocked(callingUid,
+                        targetPkg, intent, null, targetUserId);
+            }
+        }
+
+        @Override
         public String checkContentProviderAccess(String authority, int userId) {
             return ActivityManagerService.this.checkContentProviderAccess(authority, userId);
         }
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index facfeb6..32dec96 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -5,6 +5,8 @@
 import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
+
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityStack.STACK_INVISIBLE;
@@ -78,7 +80,7 @@
         if (stack.mStackId == PINNED_STACK_ID) {
             stack = mSupervisor.findStackBehind(stack);
         }
-        if (stack.mStackId == HOME_STACK_ID
+        if (StackId.isHomeOrRecentsStack(stack.mStackId)
                 || stack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
             mWindowState = WINDOW_STATE_STANDARD;
         } else if (stack.mStackId == DOCKED_STACK_ID) {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 214a357..d2a560f 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -19,7 +19,9 @@
 import static android.app.ActivityManager.StackId;
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.HOME_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
@@ -1197,10 +1199,11 @@
         }
 
         final ActivityStack stack = getStack();
-        if (stack.isHomeStack()) {
+        if (stack.isHomeOrRecentsStack()) {
             // This is an optimization -- since we never show Home or Recents within Recents itself,
             // we can just go ahead and skip taking the screenshot if this is the home stack.
-            if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tHome stack");
+            if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, stack.getStackId() == HOME_STACK_ID ?
+                        "\tHome stack" : "\tRecents stack");
             return null;
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 005b8aa..d94d3cd 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -22,6 +22,7 @@
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
 import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
@@ -690,6 +691,10 @@
         return mStackId == HOME_STACK_ID;
     }
 
+    final boolean isHomeOrRecentsStack() {
+        return StackId.isHomeOrRecentsStack(mStackId);
+    }
+
     final boolean isDockedStack() {
         return mStackId == DOCKED_STACK_ID;
     }
@@ -1450,10 +1455,10 @@
                     return false;
                 }
 
-                if (!isHomeStack() && r.frontOfTask
-                        && task.isOverHomeStack() && stackBehindId != HOME_STACK_ID) {
+                if (!isHomeOrRecentsStack() && r.frontOfTask
+                        && task.isOverHomeStack() && !StackId.isHomeOrRecentsStack(stackBehindId)) {
                     // Stack isn't translucent if it's top activity should have the home stack
-                    // behind it and the stack currently behind it isn't the home stack.
+                    // behind it and the stack currently behind it isn't the home or recents stack.
                     return false;
                 }
             }
@@ -1519,10 +1524,10 @@
         }
 
         if (mStackId == FULLSCREEN_WORKSPACE_STACK_ID
-                && hasVisibleBehindActivity() && focusedStackId == HOME_STACK_ID
+                && hasVisibleBehindActivity() && StackId.isHomeOrRecentsStack(focusedStackId)
                 && !focusedStack.topActivity().fullscreen) {
             // The fullscreen stack should be visible if it has a visible behind activity behind
-            // the home stack that is translucent.
+            // the home or recents stack that is translucent.
             return STACK_VISIBLE_ACTIVITY_BEHIND;
         }
 
@@ -1825,11 +1830,10 @@
             // If keyguard is showing, nothing is visible, except if we are able to dismiss Keyguard
             // right away.
             return shouldBeVisible && mStackSupervisor.mKeyguardController
-                    .canShowActivityWhileKeyguardShowing(dismissKeyguard);
+                    .canShowActivityWhileKeyguardShowing(r, dismissKeyguard);
         } else if (keyguardLocked) {
-
-            // Show when locked windows above keyguard.
-            return shouldBeVisible && showWhenLocked;
+            return shouldBeVisible && mStackSupervisor.mKeyguardController.canShowWhileOccluded(
+                    dismissKeyguard, showWhenLocked);
         } else {
             return shouldBeVisible;
         }
@@ -1922,7 +1926,7 @@
                         + " behindFullscreenActivity=" + behindFullscreenActivity);
             // At this point, nothing else needs to be shown in this task.
             behindFullscreenActivity = true;
-        } else if (!isHomeStack() && r.frontOfTask && task.isOverHomeStack()) {
+        } else if (!isHomeOrRecentsStack() && r.frontOfTask && task.isOverHomeStack()) {
             if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Showing home: at " + r
                     + " stackInvisible=" + stackInvisible
                     + " behindFullscreenActivity=" + behindFullscreenActivity);
@@ -2096,9 +2100,7 @@
         if (next == null) {
             // There are no more activities!
             final String reason = "noMoreActivities";
-            final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack()
-                    ? HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
-            if (!mFullscreen && adjustFocusToNextFocusableStackLocked(returnTaskType, reason)) {
+            if (!mFullscreen && adjustFocusToNextFocusableStackLocked(reason)) {
                 // Try to move focus to the next visible stack with a running activity if this
                 // stack is not covering the entire screen.
                 return mStackSupervisor.resumeFocusedStackTopActivityLocked(
@@ -2112,7 +2114,7 @@
             if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
             // Only resume home if on home display
             return isOnHomeDisplay() &&
-                    mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, reason);
+                    mStackSupervisor.resumeHomeStackTask(prev, reason);
         }
 
         next.delayedResume = false;
@@ -2147,10 +2149,8 @@
             } else if (!isHomeStack()){
                 if (DEBUG_STATES) Slog.d(TAG_STATES,
                         "resumeTopActivityLocked: Launching home next");
-                final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?
-                        HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
                 return isOnHomeDisplay() &&
-                        mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, "prevFinished");
+                        mStackSupervisor.resumeHomeStackTask(prev, "prevFinished");
             }
         }
 
@@ -2567,7 +2567,7 @@
         // activity, set mTaskToReturnTo accordingly.
         if (isOnHomeDisplay()) {
             ActivityStack lastStack = mStackSupervisor.getLastStack();
-            final boolean fromHome = lastStack.isHomeStack();
+            final boolean fromHomeOrRecents = lastStack.isHomeOrRecentsStack();
             final boolean fromOnTopLauncher = lastStack.topTask() != null &&
                     lastStack.topTask().isOnTopLauncher();
             if (fromOnTopLauncher) {
@@ -2576,12 +2576,12 @@
                 // This also makes sure that non-home activities are visible under a transparent
                 // non-home activity.
                 task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
-            } else if (!isHomeStack() && (fromHome || topTask() != task)) {
+            } else if (!isHomeOrRecentsStack() && (fromHomeOrRecents || topTask() != task)) {
                 // If it's a last task over home - we default to keep its return to type not to
                 // make underlying task focused when this one will be finished.
                 int returnToType = isLastTaskOverHome
                         ? task.getTaskToReturnTo() : APPLICATION_ACTIVITY_TYPE;
-                if (fromHome && StackId.allowTopTaskToReturnHome(mStackId)) {
+                if (fromHomeOrRecents && StackId.allowTopTaskToReturnHome(mStackId)) {
                     returnToType = lastStack.topTask() == null
                             ? HOME_ACTIVITY_TYPE : lastStack.topTask().taskType;
                 }
@@ -2675,7 +2675,7 @@
         task.setFrontOfTask();
 
         r.putInHistory();
-        if (!isHomeStack() || numActivities() > 0) {
+        if (!isHomeOrRecentsStack() || numActivities() > 0) {
             // We want to show the starting preview window if we are
             // switching to a new task, or the next activity's process is
             // not currently running.
@@ -3114,18 +3114,16 @@
             } else {
                 final TaskRecord task = r.task;
                 if (r.frontOfTask && task == topTask() && task.isOverHomeStack()) {
-                    final int taskToReturnTo = task.getTaskToReturnTo();
-
                     // For non-fullscreen stack, we want to move the focus to the next visible
                     // stack to prevent the home screen from moving to the top and obscuring
                     // other visible stacks.
                     if (!mFullscreen
-                            && adjustFocusToNextFocusableStackLocked(taskToReturnTo, myReason)) {
+                            && adjustFocusToNextFocusableStackLocked(myReason)) {
                         return;
                     }
                     // Move the home stack to the top if this stack is fullscreen or there is no
                     // other visible stack.
-                    if (mStackSupervisor.moveHomeStackTaskToTop(taskToReturnTo, myReason)) {
+                    if (mStackSupervisor.moveHomeStackTaskToTop(myReason)) {
                         // Activity focus was already adjusted. Nothing else to do...
                         return;
                     }
@@ -3137,7 +3135,7 @@
                 mStackSupervisor.topRunningActivityLocked(), myReason);
     }
 
-    private boolean adjustFocusToNextFocusableStackLocked(int taskToReturnTo, String reason) {
+    private boolean adjustFocusToNextFocusableStackLocked(String reason) {
         final ActivityStack stack = getNextFocusableStackLocked();
         final String myReason = reason + " adjustFocusToNextFocusableStack";
         if (stack == null) {
@@ -3146,10 +3144,10 @@
 
         final ActivityRecord top = stack.topRunningActivityLocked();
 
-        if (stack.isHomeStack() && (top == null || !top.visible)) {
+        if (stack.isHomeOrRecentsStack() && (top == null || !top.visible)) {
             // If we will be focusing on the home stack next and its current top activity isn't
             // visible, then use the task return to value to determine the home task to display next.
-            return mStackSupervisor.moveHomeStackTaskToTop(taskToReturnTo, reason);
+            return mStackSupervisor.moveHomeStackTaskToTop(reason);
         }
 
         stack.moveToFront(myReason);
@@ -3754,7 +3752,7 @@
                     "removeActivityFromHistoryLocked: last activity removed from " + this);
             if (mStackSupervisor.isFocusedStack(this) && task == topTask() &&
                     task.isOverHomeStack()) {
-                mStackSupervisor.moveHomeStackTaskToTop(task.getTaskToReturnTo(), reason);
+                mStackSupervisor.moveHomeStackTaskToTop(reason);
             }
             removeTask(task, reason);
         }
@@ -4176,11 +4174,11 @@
         mStackSupervisor.invalidateTaskLayers();
     }
 
-    void moveHomeStackTaskToTop(int homeStackTaskType) {
+    void moveHomeStackTaskToTop() {
         final int top = mTaskHistory.size() - 1;
         for (int taskNdx = top; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
-            if (task.taskType == homeStackTaskType) {
+            if (task.taskType == HOME_ACTIVITY_TYPE) {
                 if (DEBUG_TASKS || DEBUG_STACK) Slog.d(TAG_STACK,
                         "moveHomeStackTaskToTop: moving " + task);
                 mTaskHistory.remove(taskNdx);
@@ -4306,7 +4304,7 @@
                 moveToBack(topTask());
 
                 // Resume an activity in the next focusable stack.
-                adjustFocusToNextFocusableStackLocked(APPLICATION_ACTIVITY_TYPE, "moveTaskToBack");
+                adjustFocusToNextFocusableStackLocked("moveTaskToBack");
                 mStackSupervisor.resumeFocusedStackTopActivityLocked();
                 return true;
             }
@@ -4365,9 +4363,8 @@
                 // Not ready yet!
                 return false;
             }
-            final int taskToReturnTo = tr.getTaskToReturnTo();
             tr.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
-            return mStackSupervisor.resumeHomeStackTask(taskToReturnTo, null, "moveTaskToBack");
+            return mStackSupervisor.resumeHomeStackTask(null, "moveTaskToBack");
         }
 
         mStackSupervisor.resumeFocusedStackTopActivityLocked();
@@ -4840,9 +4837,7 @@
             if (isOnHomeDisplay() && mode != REMOVE_TASK_MODE_MOVING_TO_TOP
                     && mStackSupervisor.isFocusedStack(this)) {
                 String myReason = reason + " leftTaskHistoryEmpty";
-                if (mFullscreen
-                        || !adjustFocusToNextFocusableStackLocked(
-                        task.getTaskToReturnTo(), myReason)) {
+                if (mFullscreen || !adjustFocusToNextFocusableStackLocked(myReason)) {
                     mStackSupervisor.moveHomeStackToFront(myReason);
                 }
             }
@@ -4850,7 +4845,7 @@
                 mStacks.remove(this);
                 mStacks.add(0, this);
             }
-            if (!isHomeStack()) {
+            if (!isHomeOrRecentsStack()) {
                 mActivityContainer.onTaskListEmptyLocked();
             }
         }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index eb34669..dde948f 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -33,6 +33,7 @@
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.app.ActivityManager.StackId.LAST_STATIC_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -72,7 +73,6 @@
 import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
 import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
 import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
 import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING;
@@ -661,13 +661,8 @@
     }
 
     /** Returns true if the focus activity was adjusted to the home stack top activity. */
-    boolean moveHomeStackTaskToTop(int homeStackTaskType, String reason) {
-        if (homeStackTaskType == RECENTS_ACTIVITY_TYPE) {
-            mWindowManager.showRecentApps(false /* fromHome */);
-            return false;
-        }
-
-        mHomeStack.moveHomeStackTaskToTop(homeStackTaskType);
+    boolean moveHomeStackTaskToTop(String reason) {
+        mHomeStack.moveHomeStackTaskToTop();
 
         final ActivityRecord top = getHomeActivity();
         if (top == null) {
@@ -677,22 +672,17 @@
         return true;
     }
 
-    boolean resumeHomeStackTask(int homeStackTaskType, ActivityRecord prev, String reason) {
+    boolean resumeHomeStackTask(ActivityRecord prev, String reason) {
         if (!mService.mBooting && !mService.mBooted) {
             // Not ready yet!
             return false;
         }
 
-        if (homeStackTaskType == RECENTS_ACTIVITY_TYPE) {
-            mWindowManager.showRecentApps(false /* fromHome */);
-            return false;
-        }
-
         if (prev != null) {
             prev.task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
         }
 
-        mHomeStack.moveHomeStackTaskToTop(homeStackTaskType);
+        mHomeStack.moveHomeStackTaskToTop();
         ActivityRecord r = getHomeActivity();
         final String myReason = reason + " resumeHomeStackTask";
 
@@ -2754,7 +2744,7 @@
             final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
             for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
-                if (!r.isApplicationActivity() && !stack.isHomeStack()) {
+                if (!r.isApplicationActivity() && !stack.isHomeOrRecentsStack()) {
                     if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping stack: (home activity) " + stack);
                     continue;
                 }
@@ -3178,7 +3168,7 @@
             stack.moveToFront("switchUserOnHomeDisplay");
         } else {
             // Stack was moved to another display while user was swapped out.
-            resumeHomeStackTask(HOME_ACTIVITY_TYPE, null, "switchUserOnOtherDisplay");
+            resumeHomeStackTask(null, "switchUserOnOtherDisplay");
         }
         return homeInFront;
     }
@@ -3561,6 +3551,11 @@
         }
     }
 
+    /** Check if display with specified id is added to the list. */
+    boolean isDisplayAdded(int displayId) {
+        return mActivityDisplays.get(displayId) != null;
+    }
+
     private void calculateDefaultMinimalSizeOfResizeableTasks(ActivityDisplay display) {
         mDefaultMinSizeOfResizeableTask =
                 mService.mContext.getResources().getDimensionPixelSize(
@@ -4592,9 +4587,9 @@
                 ? new ActivityOptions(bOptions) : null;
         final int launchStackId = (activityOptions != null)
                 ? activityOptions.getLaunchStackId() : INVALID_STACK_ID;
-        if (launchStackId == HOME_STACK_ID) {
+        if (StackId.isHomeOrRecentsStack(launchStackId)) {
             throw new IllegalArgumentException("startActivityFromRecentsInner: Task "
-                    + taskId + " can't be launch in the home stack.");
+                    + taskId + " can't be launch in the home/recents stack.");
         }
 
         if (launchStackId == DOCKED_STACK_ID) {
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index dff7cef..64bf3ad 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -32,6 +32,7 @@
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.app.ActivityManager.StackId.isStaticStack;
+import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
@@ -589,7 +590,7 @@
     }
 
     void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) {
-        mSupervisor.moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE, reason);
+        mSupervisor.moveHomeStackTaskToTop(reason);
         startActivityLocked(null /*caller*/, intent, null /*ephemeralIntent*/,
                 null /*resolvedType*/, aInfo, null /*rInfo*/, null /*voiceSession*/,
                 null /*voiceInteractor*/, null /*resultTo*/, null /*resultWho*/,
@@ -1524,8 +1525,8 @@
 
     private void updateTaskReturnToType(
             TaskRecord task, int launchFlags, ActivityStack focusedStack) {
-        if (focusedStack != null && focusedStack.isHomeStack() && focusedStack.topTask() != null
-                && focusedStack.topTask().isOnTopLauncher()) {
+        if (focusedStack != null && focusedStack.isHomeOrRecentsStack()
+                && focusedStack.topTask() != null && focusedStack.topTask().isOnTopLauncher()) {
             // Since an on-top launcher will is moved to back when tasks are launched from it,
             // those tasks should first try to return to a non-home activity.
             // This also makes sure that non-home activities are visible under a transparent
@@ -1869,7 +1870,10 @@
     private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, Rect bounds,
             int launchFlags, ActivityOptions aOptions) {
         final TaskRecord task = r.task;
-        if (!(r.isApplicationActivity() || (task != null && task.isApplicationTask()))) {
+        if (r.isRecentsActivity()) {
+            return mSupervisor.getStack(RECENTS_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
+        }
+        if (r.isHomeActivity()) {
             return mSupervisor.mHomeStack;
         }
 
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 67cac47..0ea78b3 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1283,7 +1283,7 @@
 
         if (useCheckinFormat) {
             List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(
-                    PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_ALL);
+                    PackageManager.MATCH_ANY_USER | PackageManager.MATCH_ALL);
             if (isRealCheckin) {
                 // For a real checkin, first we want to prefer to use the last complete checkin
                 // file if there is one.
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index 5e02597..19bf536 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -57,6 +57,7 @@
     private boolean mKeyguardShowing;
     private boolean mKeyguardGoingAway;
     private boolean mOccluded;
+    private boolean mDismissalRequested;
     private ActivityRecord mDismissingKeyguardActivity;
     private int mBeforeUnoccludeTransit;
     private int mVisibilityTransactionDepth;
@@ -95,9 +96,7 @@
         mKeyguardShowing = showing;
         if (showing) {
             mKeyguardGoingAway = false;
-
-            // Allow an activity to redismiss Keyguard.
-            mDismissingKeyguardActivity = null;
+            mDismissalRequested = false;
         }
         mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
         mService.updateSleepIfNeededLocked();
@@ -183,8 +182,20 @@
      * @return True if we may show an activity while Keyguard is showing because we are in the
      *         process of dismissing it anyways, false otherwise.
      */
-    boolean canShowActivityWhileKeyguardShowing(boolean dismissKeyguard) {
-        return dismissKeyguard && canDismissKeyguard();
+    boolean canShowActivityWhileKeyguardShowing(ActivityRecord r, boolean dismissKeyguard) {
+
+        // Allow to show it when we are about to dismiss Keyguard. This isn't allowed if r is
+        // already the dismissing activity, in which case we don't allow it to repeatedly dismiss
+        // Keyguard.
+        return dismissKeyguard && canDismissKeyguard() &&
+                (mDismissalRequested || r != mDismissingKeyguardActivity);
+    }
+
+    /**
+     * @return True if we may show an activity while Keyguard is occluded, false otherwise.
+     */
+    boolean canShowWhileOccluded(boolean dismissKeyguard, boolean showWhenLocked) {
+        return showWhenLocked || dismissKeyguard && !mWindowManager.isKeyguardSecure();
     }
 
     private void visibilitiesUpdated() {
@@ -199,7 +210,14 @@
 
             // Only the very top activity may control occluded state
             if (stackNdx == topStackNdx) {
-                mOccluded = stack.topActivityOccludesKeyguard();
+
+                // A dismissing activity occludes Keyguard in the insecure case for legacy reasons.
+                final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
+                mOccluded = stack.topActivityOccludesKeyguard()
+                        || (topDismissing != null
+                                && stack.topRunningActivityLocked() == topDismissing
+                                && canShowWhileOccluded(true /* dismissKeyguard */,
+                                        false /* showWhenLocked */));
             }
             if (mDismissingKeyguardActivity == null
                     && stack.getTopDismissingKeyguardActivity() != null) {
@@ -239,8 +257,13 @@
      * Called when somebody might want to dismiss the Keyguard.
      */
     private void handleDismissKeyguard() {
-        if (mDismissingKeyguardActivity != null) {
+        // We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy
+        // reasons, because that's how apps used to dismiss Keyguard in the secure case. In the
+        // insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded.
+        if (!mOccluded && mDismissingKeyguardActivity != null
+                && mWindowManager.isKeyguardSecure()) {
             mWindowManager.dismissKeyguard(null /* callback */);
+            mDismissalRequested = true;
 
             // If we are about to unocclude the Keyguard, but we can dismiss it without security,
             // we immediately dismiss the Keyguard so the activity gets shown without a flicker.
@@ -296,6 +319,7 @@
         pw.println(prefix + "  mKeyguardGoingAway=" + mKeyguardGoingAway);
         pw.println(prefix + "  mOccluded=" + mOccluded);
         pw.println(prefix + "  mDismissingKeyguardActivity=" + mDismissingKeyguardActivity);
+        pw.println(prefix + "  mDismissalRequested=" + mDismissalRequested);
         pw.println(prefix + "  mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);
     }
 }
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index bc9bda2f..6a13d36 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -130,8 +130,8 @@
 
     void notifyTaskPersisterLocked(TaskRecord task, boolean flush) {
         final ActivityStack stack = task != null ? task.getStack() : null;
-        if (stack != null && stack.isHomeStack()) {
-            // Never persist the home stack.
+        if (stack != null && stack.isHomeOrRecentsStack()) {
+            // Never persist the home or recents stack.
             return;
         }
         syncPersistentTaskIdsLocked();
@@ -150,7 +150,7 @@
         for (int i = size() - 1; i >= 0; i--) {
             final TaskRecord task = get(i);
             final ActivityStack stack = task.getStack();
-            if (task.isPersistable && (stack == null || !stack.isHomeStack())) {
+            if (task.isPersistable && (stack == null || !stack.isHomeOrRecentsStack())) {
                 // Set of persisted taskIds for task.userId should not be null here
                 // TODO Investigate why it can happen. For now initialize with an empty set
                 if (mPersistedTaskIds.get(task.userId) == null) {
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index 1ecb2e9..7a62f2c 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -643,7 +643,7 @@
                                     " persistable=" + task.isPersistable);
                             final ActivityStack stack = task.getStack();
                             if ((task.isPersistable || task.inRecents)
-                                    && (stack == null || !stack.isHomeStack())) {
+                                    && (stack == null || !stack.isHomeOrRecentsStack())) {
                                 if (DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task);
                                 persistentTaskIds.add(task.taskId);
                             } else {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 86e3ccc..5c352e1 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -64,6 +64,7 @@
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
 import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
 import static android.content.pm.ActivityInfo.FLAG_ON_TOP_LAUNCHER;
@@ -1068,7 +1069,7 @@
     }
 
     boolean isOverHomeStack() {
-        return mTaskToReturnTo == HOME_ACTIVITY_TYPE || mTaskToReturnTo == RECENTS_ACTIVITY_TYPE;
+        return mTaskToReturnTo == HOME_ACTIVITY_TYPE;
     }
 
     boolean isResizeable() {
@@ -1417,8 +1418,8 @@
                 try {
                     ApplicationInfo ai = pm.getApplicationInfo(
                             checkIntent.getComponent().getPackageName(),
-                            PackageManager.GET_UNINSTALLED_PACKAGES
-                                    | PackageManager.GET_DISABLED_COMPONENTS, userId);
+                            PackageManager.MATCH_UNINSTALLED_PACKAGES
+                                    | PackageManager.MATCH_DISABLED_COMPONENTS, userId);
                     if (ai != null) {
                         effectiveUid = ai.uid;
                     }
@@ -1685,7 +1686,10 @@
      * The task will be moved (and stack focus changed) later if necessary.
      */
     int getLaunchStackId() {
-        if (!isApplicationTask()) {
+        if (isRecentsTask()) {
+            return RECENTS_STACK_ID;
+        }
+        if (isHomeTask()) {
             return HOME_STACK_ID;
         }
         if (mBounds != null) {
@@ -1707,6 +1711,7 @@
 
         final int stackId = mStack.mStackId;
         if (stackId == HOME_STACK_ID
+                || stackId == RECENTS_STACK_ID
                 || stackId == FULLSCREEN_WORKSPACE_STACK_ID
                 || (stackId == DOCKED_STACK_ID && !isResizeable())) {
             return isResizeable() ? mStack.mBounds : null;
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index aa66917..5e98859 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -97,6 +97,24 @@
     private static final int SOCKET_TIMEOUT_MS = 10000;
     private static final int PROBE_TIMEOUT_MS  = 3000;
 
+    static enum EvaluationResult {
+        VALIDATED(true),
+        CAPTIVE_PORTAL(false);
+        final boolean isValidated;
+        EvaluationResult(boolean isValidated) {
+            this.isValidated = isValidated;
+        }
+    }
+
+    static enum ValidationStage {
+        FIRST_VALIDATION(true),
+        REVALIDATION(false);
+        final boolean isFirstValidation;
+        ValidationStage(boolean isFirstValidation) {
+            this.isFirstValidation = isFirstValidation;
+        }
+    }
+
     public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
             "android.net.conn.NETWORK_CONDITIONS_MEASURED";
     public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type";
@@ -216,6 +234,8 @@
     protected boolean mIsCaptivePortalCheckEnabled;
 
     private boolean mUseHttps;
+    // The total number of captive portal detection attempts for this NetworkMonitor instance.
+    private int mValidations = 0;
 
     // Set if the user explicitly selected "Do not use this network" in captive portal sign-in app.
     private boolean mUserDoesNotWant = false;
@@ -290,6 +310,10 @@
         return validationLogs.readOnlyLocalLog();
     }
 
+    private ValidationStage validationStage() {
+        return 0 == mValidations ? ValidationStage.FIRST_VALIDATION : ValidationStage.REVALIDATION;
+    }
+
     // DefaultState is the parent of all States.  It exists only to handle CMD_* messages but
     // does not entail any real state (hence no enter() or exit() routines).
     private class DefaultState extends State {
@@ -366,9 +390,11 @@
     private class ValidatedState extends State {
         @Override
         public void enter() {
-            maybeLogEvaluationResult(NetworkEvent.NETWORK_VALIDATED);
+            maybeLogEvaluationResult(
+                    networkEventType(validationStage(), EvaluationResult.VALIDATED));
             mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
                     NETWORK_TEST_RESULT_VALID, mNetworkAgentInfo.network.netId, null));
+            mValidations++;
         }
 
         @Override
@@ -584,7 +610,8 @@
 
         @Override
         public void enter() {
-            maybeLogEvaluationResult(NetworkEvent.NETWORK_CAPTIVE_PORTAL_FOUND);
+            maybeLogEvaluationResult(
+                    networkEventType(validationStage(), EvaluationResult.CAPTIVE_PORTAL));
             // Don't annoy user with sign-in notifications.
             if (mDontDisplaySigninNotification) return;
             // Create a CustomIntentReceiver that sends us a
@@ -604,6 +631,7 @@
             // Retest for captive portal occasionally.
             sendMessageDelayed(CMD_CAPTIVE_PORTAL_RECHECK, 0 /* no UID */,
                     CAPTIVE_PORTAL_REEVALUATE_DELAY_MS);
+            mValidations++;
         }
 
         @Override
@@ -679,48 +707,13 @@
 
         long startTime = SystemClock.elapsedRealtime();
 
-        // Pre-resolve the captive portal server host so we can log it.
-        // Only do this if HttpURLConnection is about to, to avoid any potentially
-        // unnecessary resolution.
-        String hostToResolve = null;
+        final CaptivePortalProbeResult result;
         if (pacUrl != null) {
-            hostToResolve = pacUrl.getHost();
-        } else if (proxyInfo != null) {
-            hostToResolve = proxyInfo.getHost();
-        } else {
-            hostToResolve = httpUrl.getHost();
-        }
-
-        if (!TextUtils.isEmpty(hostToResolve)) {
-            String probeName = ValidationProbeEvent.getProbeName(ValidationProbeEvent.PROBE_DNS);
-            final Stopwatch dnsTimer = new Stopwatch().start();
-            int dnsResult;
-            long dnsLatency;
-            try {
-                InetAddress[] addresses = mNetworkAgentInfo.network.getAllByName(hostToResolve);
-                dnsResult = ValidationProbeEvent.DNS_SUCCESS;
-                dnsLatency = dnsTimer.stop();
-                final StringBuffer connectInfo = new StringBuffer(", " + hostToResolve + "=");
-                for (InetAddress address : addresses) {
-                    connectInfo.append(address.getHostAddress());
-                    if (address != addresses[addresses.length-1]) connectInfo.append(",");
-                }
-                validationLog(probeName + " OK " + dnsLatency + "ms" + connectInfo);
-            } catch (UnknownHostException e) {
-                dnsResult = ValidationProbeEvent.DNS_FAILURE;
-                dnsLatency = dnsTimer.stop();
-                validationLog(probeName + " FAIL " + dnsLatency + "ms, " + hostToResolve);
-            }
-            logValidationProbe(dnsLatency, ValidationProbeEvent.PROBE_DNS, dnsResult);
-        }
-
-        CaptivePortalProbeResult result;
-        if (pacUrl != null) {
-            result = sendHttpProbe(pacUrl, ValidationProbeEvent.PROBE_PAC);
+            result = sendDnsAndHttpProbes(null, pacUrl, ValidationProbeEvent.PROBE_PAC);
         } else if (mUseHttps) {
-            result = sendParallelHttpProbes(httpsUrl, httpUrl, fallbackUrl);
+            result = sendParallelHttpProbes(proxyInfo, httpsUrl, httpUrl, fallbackUrl);
         } else {
-            result = sendHttpProbe(httpUrl, ValidationProbeEvent.PROBE_HTTP);
+            result = sendDnsAndHttpProbes(proxyInfo, httpUrl, ValidationProbeEvent.PROBE_HTTP);
         }
 
         long endTime = SystemClock.elapsedRealtime();
@@ -733,8 +726,50 @@
     }
 
     /**
-     * Do a URL fetch on a known server to see if we get the data we expect.
-     * Returns HTTP response code.
+     * Do a DNS resolution and URL fetch on a known web server to see if we get the data we expect.
+     * @return a CaptivePortalProbeResult inferred from the HTTP response.
+     */
+    private CaptivePortalProbeResult sendDnsAndHttpProbes(ProxyInfo proxy, URL url, int probeType) {
+        // Pre-resolve the captive portal server host so we can log it.
+        // Only do this if HttpURLConnection is about to, to avoid any potentially
+        // unnecessary resolution.
+        final String host = (proxy != null) ? proxy.getHost() : url.getHost();
+        sendDnsProbe(host);
+        return sendHttpProbe(url, probeType);
+    }
+
+    /** Do a DNS resolution of the given server. */
+    private void sendDnsProbe(String host) {
+        if (TextUtils.isEmpty(host)) {
+            return;
+        }
+
+        final String name = ValidationProbeEvent.getProbeName(ValidationProbeEvent.PROBE_DNS);
+        final Stopwatch watch = new Stopwatch().start();
+        int result;
+        String connectInfo;
+        try {
+            InetAddress[] addresses = mNetworkAgentInfo.network.getAllByName(host);
+            result = ValidationProbeEvent.DNS_SUCCESS;
+            StringBuffer buffer = new StringBuffer(host).append("=");
+            for (InetAddress address : addresses) {
+                buffer.append(address.getHostAddress());
+                if (address != addresses[addresses.length-1]) buffer.append(",");
+            }
+            connectInfo = buffer.toString();
+        } catch (UnknownHostException e) {
+            result = ValidationProbeEvent.DNS_FAILURE;
+            connectInfo = host;
+        }
+        final long latency = watch.stop();
+        String resultString = (ValidationProbeEvent.DNS_SUCCESS == result) ? "OK" : "FAIL";
+        validationLog(String.format("%s %s %dms, %s", name, resultString, latency, connectInfo));
+        logValidationProbe(latency, ValidationProbeEvent.PROBE_DNS, result);
+    }
+
+    /**
+     * Do a URL fetch on a known web server to see if we get the data we expect.
+     * @return a CaptivePortalProbeResult inferred from the HTTP response.
      */
     @VisibleForTesting
     protected CaptivePortalProbeResult sendHttpProbe(URL url, int probeType) {
@@ -801,7 +836,7 @@
     }
 
     private CaptivePortalProbeResult sendParallelHttpProbes(
-            URL httpsUrl, URL httpUrl, URL fallbackUrl) {
+            ProxyInfo proxy, URL httpsUrl, URL httpUrl, URL fallbackUrl) {
         // Number of probes to wait for. If a probe completes with a conclusive answer
         // it shortcuts the latch immediately by forcing the count to 0.
         final CountDownLatch latch = new CountDownLatch(2);
@@ -821,9 +856,10 @@
             @Override
             public void run() {
                 if (mIsHttps) {
-                    mResult = sendHttpProbe(httpsUrl, ValidationProbeEvent.PROBE_HTTPS);
+                    mResult =
+                            sendDnsAndHttpProbes(proxy, httpsUrl, ValidationProbeEvent.PROBE_HTTPS);
                 } else {
-                    mResult = sendHttpProbe(httpUrl, ValidationProbeEvent.PROBE_HTTP);
+                    mResult = sendDnsAndHttpProbes(proxy, httpUrl, ValidationProbeEvent.PROBE_HTTP);
                 }
                 if ((mIsHttps && mResult.isSuccessful()) || (!mIsHttps && mResult.isPortal())) {
                     // Stop waiting immediately if https succeeds or if http finds a portal.
@@ -974,6 +1010,22 @@
         mMetricsLog.log(new NetworkEvent(mNetId, evtype));
     }
 
+    private int networkEventType(ValidationStage s, EvaluationResult r) {
+        if (s.isFirstValidation) {
+            if (r.isValidated) {
+                return NetworkEvent.NETWORK_FIRST_VALIDATION_SUCCESS;
+            } else {
+                return NetworkEvent.NETWORK_FIRST_VALIDATION_PORTAL_FOUND;
+            }
+        } else {
+            if (r.isValidated) {
+                return NetworkEvent.NETWORK_REVALIDATION_SUCCESS;
+            } else {
+                return NetworkEvent.NETWORK_REVALIDATION_PORTAL_FOUND;
+            }
+        }
+    }
+
     private void maybeLogEvaluationResult(int evtype) {
         if (mEvaluationTimer.isRunning()) {
             mMetricsLog.log(new NetworkEvent(mNetId, evtype, mEvaluationTimer.stop()));
@@ -982,6 +1034,8 @@
     }
 
     private void logValidationProbe(long durationMs, int probeType, int probeResult) {
+        probeType =
+                ValidationProbeEvent.makeProbeType(probeType, validationStage().isFirstValidation);
         mMetricsLog.log(new ValidationProbeEvent(mNetId, durationMs, probeType, probeResult));
     }
 }
diff --git a/services/core/java/com/android/server/firewall/SenderPackageFilter.java b/services/core/java/com/android/server/firewall/SenderPackageFilter.java
index 91c9671..2184245 100644
--- a/services/core/java/com/android/server/firewall/SenderPackageFilter.java
+++ b/services/core/java/com/android/server/firewall/SenderPackageFilter.java
@@ -47,7 +47,7 @@
         try {
             // USER_SYSTEM here is not important. Only app id is used and getPackageUid() will
             // return a uid whether the app is installed for a user or not.
-            packageUid = pm.getPackageUid(mPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES,
+            packageUid = pm.getPackageUid(mPackageName, PackageManager.MATCH_ANY_USER,
                     UserHandle.USER_SYSTEM);
         } catch (RemoteException ex) {
             // handled below
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index c99d8be..f42c5be 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -1820,7 +1820,7 @@
                 String pkg = args[opti];
                 try {
                     filterUid = getContext().getPackageManager().getPackageUid(pkg,
-                            PackageManager.MATCH_UNINSTALLED_PACKAGES);
+                            PackageManager.MATCH_ANY_USER);
                 } catch (NameNotFoundException ignored) {
                     pw.println("Invalid package: " + pkg);
                     return;
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 45f54a9..54366e6 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -95,7 +95,8 @@
 import java.util.Date;
 import java.util.Map.Entry;
 import java.util.Properties;
-
+import java.util.Map;
+import java.util.HashMap;
 import libcore.io.IoUtils;
 
 /**
@@ -211,24 +212,18 @@
     private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
     private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2;
 
-    // Request ref location
-    private static final int AGPS_RIL_REQUEST_REFLOC_CELLID = 1;
-    private static final int AGPS_RIL_REQUEST_REFLOC_MAC = 2;
+    //TODO(b/33112647): Create gps_debug.conf with commented career parameters.
+    private static final String DEBUG_PROPERTIES_FILE = "/etc/gps_debug.conf";
 
     // ref. location info
     private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1;
     private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2;
-    private static final int AGPS_REG_LOCATION_TYPE_MAC        = 3;
 
     // set id info
     private static final int AGPS_SETID_TYPE_NONE = 0;
     private static final int AGPS_SETID_TYPE_IMSI = 1;
     private static final int AGPS_SETID_TYPE_MSISDN = 2;
 
-    private static final String PROPERTIES_FILE_PREFIX = "/etc/gps";
-    private static final String PROPERTIES_FILE_SUFFIX = ".conf";
-    private static final String DEFAULT_PROPERTIES_FILE = PROPERTIES_FILE_PREFIX + PROPERTIES_FILE_SUFFIX;
-
     private static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L;
     private static final int GPS_GEOFENCE_AVAILABLE = 1<<1L;
 
@@ -501,10 +496,6 @@
                 startNavigating(false);
             } else if (action.equals(ALARM_TIMEOUT)) {
                 hibernate();
-            } else if (action.equals(Intents.DATA_SMS_RECEIVED_ACTION)) {
-                checkSmsSuplInit(intent);
-            } else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) {
-                checkWapSuplInit(intent);
             } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)
                     || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)
                     || Intent.ACTION_SCREEN_OFF.equals(action)
@@ -557,31 +548,6 @@
         }
     }
 
-    private void checkSmsSuplInit(Intent intent) {
-        SmsMessage[] messages = Intents.getMessagesFromIntent(intent);
-        if (messages == null) {
-            Log.e(TAG, "Message does not exist in the intent.");
-            return;
-        }
-
-        for (SmsMessage message : messages) {
-            if (message != null && message.mWrappedSmsMessage != null) {
-                byte[] suplInit = message.getUserData();
-                if (suplInit != null) {
-                    native_agps_ni_message(suplInit, suplInit.length);
-                }
-            }
-        }
-    }
-
-    private void checkWapSuplInit(Intent intent) {
-        byte[] suplInit = intent.getByteArrayExtra("data");
-        if (suplInit == null) {
-            return;
-        }
-        native_agps_ni_message(suplInit,suplInit.length);
-    }
-
     private void updateLowPowerMode() {
         // Disable GPS if we are in device idle mode.
         boolean disableGps = mPowerManager.isDeviceIdleMode();
@@ -602,23 +568,14 @@
         return native_is_supported();
     }
 
+    interface SetCarrierProperty {
+        public boolean set(int value);
+    }
+
     private void reloadGpsProperties(Context context, Properties properties) {
         if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + properties.size());
         loadPropertiesFromResource(context, properties);
 
-        boolean isPropertiesLoadedFromFile = false;
-        final String gpsHardware = SystemProperties.get("ro.hardware.gps");
-
-        if (!TextUtils.isEmpty(gpsHardware)) {
-            final String propFilename =
-                    PROPERTIES_FILE_PREFIX + "." + gpsHardware + PROPERTIES_FILE_SUFFIX;
-            isPropertiesLoadedFromFile =
-                    loadPropertiesFromFile(propFilename, properties);
-        }
-        if (!isPropertiesLoadedFromFile) {
-            loadPropertiesFromFile(DEFAULT_PROPERTIES_FILE, properties);
-        }
-        if (DEBUG) Log.d(TAG, "GPS properties reloaded, size = " + properties.size());
         String lpp_prof = SystemProperties.get(LPP_PROFILE);
         if (!TextUtils.isEmpty(lpp_prof)) {
                 // override default value of this if lpp_prof is not empty
@@ -636,16 +593,37 @@
                 Log.e(TAG, "unable to parse C2K_PORT: " + portString);
             }
         }
-
+        /*
+         * Allow carrier properties to be loaded from a  debug configuration file.
+         */
+        loadPropertiesFromFile(DEBUG_PROPERTIES_FILE, properties);
         if (native_is_gnss_configuration_supported()) {
-            try {
-                // Convert properties to string contents and send it to HAL.
-                ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
-                properties.store(baos, null);
-                native_configuration_update(baos.toString());
-                if (DEBUG) Log.d(TAG, "final config = " + baos.toString());
-            } catch (IOException ex) {
-                Log.e(TAG, "failed to dump properties contents");
+            Map<String, SetCarrierProperty> map = new HashMap<String, SetCarrierProperty>() {
+                {
+                    put("SUPL_VER", (val) -> native_set_supl_version(val));
+                    put("SUPL_MODE", (val) -> native_set_supl_mode(val));
+                    put("SUPL_ES", (val) -> native_set_supl_es(val));
+                    put("LPP_PROFILE", (val) -> native_set_lpp_profile(val));
+                    put("A_GLONASS_POS_PROTOCOL_SELECT", (val) -> native_set_gnss_pos_protocol_select(val));
+                    put("USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL", (val) -> native_set_emergency_supl_pdn(val));
+                    put("GPS_LOCK", (val) -> native_set_gps_lock(val));
+                }
+            };
+
+            for(Entry<String, SetCarrierProperty> entry : map.entrySet()) {
+                String propertyName = entry.getKey();
+                String propertyValueString = properties.getProperty(propertyName);
+                if (propertyValueString != null) {
+                    try {
+                          int propertyValueInt = Integer.decode(propertyValueString);
+                          boolean result = entry.getValue().set(propertyValueInt);
+                          if (result == false) {
+                              Log.e(TAG, "Unable to set " + propertyName);
+                          }
+                    } catch (NumberFormatException e) {
+                          Log.e(TAG, "unable to parse propertyName: " + propertyValueString);
+                    }
+                }
             }
         } else if (DEBUG) {
             Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not"
@@ -692,7 +670,7 @@
             }
 
         } catch (IOException e) {
-            Log.w(TAG, "Could not open GPS configuration file " + filename);
+            Log.v(TAG, "Could not open GPS configuration file " + filename);
             return false;
         }
         return true;
@@ -1973,8 +1951,7 @@
             String requestorId,
             String text,
             int requestorIdEncoding,
-            int textEncoding,
-            String extras  // Encoded extra data
+            int textEncoding
         )
     {
         Log.i(TAG, "reportNiNotification: entered");
@@ -2003,28 +1980,6 @@
         notification.requestorIdEncoding = requestorIdEncoding;
         notification.textEncoding = textEncoding;
 
-        // Process extras, assuming the format is
-        // one of more lines of "key = value"
-        Bundle bundle = new Bundle();
-
-        if (extras == null) extras = "";
-        Properties extraProp = new Properties();
-
-        try {
-            extraProp.load(new StringReader(extras));
-        }
-        catch (IOException e)
-        {
-            Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras);
-        }
-
-        for (Entry<Object, Object> ent : extraProp.entrySet())
-        {
-            bundle.putString((String) ent.getKey(), (String) ent.getValue());
-        }
-
-        notification.extras = bundle;
-
         mNIHandler.handleNiNotification(notification);
     }
 
@@ -2075,7 +2030,7 @@
      * Called from native code to request reference location info
      */
 
-    private void requestRefLocation(int flags) {
+    private void requestRefLocation() {
         TelephonyManager phone = (TelephonyManager)
                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
         final int phoneType = phone.getPhoneType();
@@ -2547,5 +2502,12 @@
     private native boolean native_stop_navigation_message_collection();
 
     // GNSS Configuration
-    private static native void native_configuration_update(String configData);
+    private static native boolean native_set_supl_version(int version);
+    private static native boolean native_set_supl_mode(int mode);
+    private static native boolean native_set_supl_es(int es);
+    private static native boolean native_set_lpp_profile(int lppProfile);
+    private static native boolean native_set_gnss_pos_protocol_select(int gnssPosProtocolSelect);
+    private static native boolean native_set_gps_lock(int gpsLock);
+    private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn);
+
 }
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index 9740935..d8fd6e2 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -74,7 +74,7 @@
         try {
             List<ActivityManager.RecentTaskInfo> tasks =
                     ActivityManager.getService().getRecentTasks(1,
-                            ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS |
+                            ActivityManager.RECENT_IGNORE_HOME_AND_RECENTS_STACK_TASKS |
                             ActivityManager.RECENT_IGNORE_UNAVAILABLE |
                             ActivityManager.RECENT_INCLUDE_PROFILES |
                             ActivityManager.RECENT_WITH_EXCLUDED, record.getUserId()).getList();
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index c1506b9..533307e 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -2720,7 +2720,7 @@
             // update rules for all installed applications
             final List<UserInfo> users = mUserManager.getUsers();
             final List<ApplicationInfo> apps = pm.getInstalledApplications(
-                    PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_DISABLED_COMPONENTS
+                    PackageManager.MATCH_ANY_USER | PackageManager.MATCH_DISABLED_COMPONENTS
                             | PackageManager.MATCH_DIRECT_BOOT_AWARE
                             | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
 
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 4658c046..8ca6086 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -1212,7 +1212,8 @@
         // Build list of UIDs that we should clean up
         int[] uids = new int[0];
         final List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(
-                PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_DISABLED_COMPONENTS);
+                PackageManager.MATCH_ANY_USER
+                | PackageManager.MATCH_DISABLED_COMPONENTS);
         for (ApplicationInfo app : apps) {
             final int uid = UserHandle.getUid(userId, app.uid);
             uids = ArrayUtils.appendInt(uids, uid);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 84c298b..c78a0f5 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -53,16 +53,17 @@
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
 import android.app.AutomaticZenRule;
+import android.app.backup.BackupManager;
 import android.app.IActivityManager;
+import android.app.IOnNotificationChannelCreatedListener;
 import android.app.INotificationManager;
 import android.app.ITransientNotification;
 import android.app.Notification;
 import android.app.NotificationChannel;
-import android.app.NotificationManager;
 import android.app.NotificationManager.Policy;
+import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
-import android.app.backup.BackupManager;
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.BroadcastReceiver;
@@ -224,6 +225,7 @@
     private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
 
     private IActivityManager mAm;
+    private IPackageManager mPackageManager;
     AudioManager mAudioManager;
     AudioManagerInternal mAudioManagerInternal;
     @Nullable StatusBarManagerInternal mStatusBar;
@@ -718,10 +720,10 @@
                     if (packageChanged) {
                         // We cancel notifications for packages which have just been disabled
                         try {
-                            final IPackageManager pm = AppGlobals.getPackageManager();
-                            final int enabled = pm.getApplicationEnabledSetting(pkgName,
+                            final int enabled = mPackageManager.getApplicationEnabledSetting(
+                                    pkgName,
                                     changeUserId != UserHandle.USER_ALL ? changeUserId :
-                                    UserHandle.USER_SYSTEM);
+                                            UserHandle.USER_SYSTEM);
                             if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                                     || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
                                 cancelNotifications = false;
@@ -884,6 +886,7 @@
         super(context);
     }
 
+    // TODO - replace these methods with a single VisibleForTesting constructor
     @VisibleForTesting
     void setAudioManager(AudioManager audioMananger) {
         mAudioManager = audioMananger;
@@ -931,6 +934,17 @@
         mFallbackVibrationPattern = vibrationPattern;
     }
 
+    @VisibleForTesting
+    void setPackageManager(IPackageManager packageManager) {
+        mPackageManager = packageManager;
+    }
+
+    // TODO: This probably should not be mocked, it's an implementation detail.
+    @VisibleForTesting
+    void setRankingHelper(RankingHelper rankingHelper) {
+        mRankingHelper = rankingHelper;
+    }
+
     @Override
     public void onStart() {
         Resources resources = getContext().getResources();
@@ -940,6 +954,7 @@
                 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
 
         mAm = ActivityManager.getService();
+        mPackageManager = AppGlobals.getPackageManager();
         mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
         mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
         mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
@@ -1312,6 +1327,11 @@
         scheduleInterruptionFilterChanged(interruptionFilter);
     }
 
+    @VisibleForTesting
+    INotificationManager getBinderService() {
+        return INotificationManager.Stub.asInterface(mService);
+    }
+
     private final IBinder mService = new INotificationManager.Stub() {
         // Toasts
         // ============================================================================
@@ -1529,13 +1549,15 @@
         }
 
         @Override
-        public void createNotificationChannel(String pkg, NotificationChannel channel) {
+        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();
+            listener.onNotificationChannelCreated(channel);
         }
 
         @Override
@@ -3906,23 +3928,23 @@
         throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
     }
 
-    private static void checkCallerIsSystemOrSameApp(String pkg) {
+    private void checkCallerIsSystemOrSameApp(String pkg) {
         if (isCallerSystem()) {
             return;
         }
         checkCallerIsSameApp(pkg);
     }
 
-    private static void checkCallerIsSameApp(String pkg) {
+    private void checkCallerIsSameApp(String pkg) {
         final int uid = Binder.getCallingUid();
         try {
-            ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
+            ApplicationInfo ai = mPackageManager.getApplicationInfo(
                     pkg, 0, UserHandle.getCallingUserId());
             if (ai == null) {
                 throw new SecurityException("Unknown package " + pkg);
             }
             if (!UserHandle.isSameApp(ai.uid, uid)) {
-                throw new SecurityException("Calling uid " + uid + " gave package"
+                throw new SecurityException("Calling uid " + uid + " gave package "
                         + pkg + " which is owned by uid " + ai.uid);
             }
         } catch (RemoteException re) {
@@ -4009,7 +4031,7 @@
     private boolean isPackageSuspendedForUser(String pkg, int uid) {
         int userId = UserHandle.getUserId(uid);
         try {
-            return AppGlobals.getPackageManager().isPackageSuspendedForUser(pkg, userId);
+            return mPackageManager.isPackageSuspendedForUser(pkg, userId);
         } catch (RemoteException re) {
             throw new SecurityException("Could not talk to package manager service");
         } catch (IllegalArgumentException ex) {
@@ -4510,7 +4532,7 @@
         }
 
         public String[] getRequestingPackages() throws RemoteException {
-            final ParceledListSlice list = AppGlobals.getPackageManager()
+            final ParceledListSlice list = mPackageManager
                     .getPackagesHoldingPermissions(PERM, 0 /*flags*/,
                             ActivityManager.getCurrentUser());
             final List<PackageInfo> pkgs = list.getList();
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 984fc38..0213258 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -169,7 +169,8 @@
                 NotificationManagerService.VIBRATE_PATTERN_MAXLEN,
                 NotificationManagerService.DEFAULT_VIBRATE_PATTERN);
         if (getChannel().shouldVibrate()) {
-            vibration = defaultVibration;
+            vibration = getChannel().getVibrationPattern() == null
+                    ? defaultVibration : getChannel().getVibrationPattern();
         } else {
             vibration = null;
         }
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 90b3715..a41231d 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -15,6 +15,8 @@
  */
 package com.android.server.notification;
 
+import static android.app.NotificationManager.IMPORTANCE_NONE;
+
 import com.android.internal.R;
 
 import android.app.Notification;
@@ -450,6 +452,9 @@
     @Override
     public void createNotificationChannel(String pkg, int uid, NotificationChannel channel) {
         Record r = getOrCreateRecord(pkg, uid);
+        if (IMPORTANCE_NONE == r.importance) {
+            throw new IllegalArgumentException("Package blocked");
+        }
         if (r.channels.containsKey(channel.getId()) || channel.getName().equals(
                 mContext.getString(R.string.default_notification_channel_label))) {
             throw new IllegalArgumentException("Channel already exists");
@@ -501,7 +506,8 @@
             channel.setSound(updatedChannel.getSound());
         }
         if ((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_VIBRATION) == 0) {
-            channel.setVibration(updatedChannel.shouldVibrate());
+            channel.enableVibration(updatedChannel.shouldVibrate());
+            channel.setVibrationPattern(updatedChannel.getVibrationPattern());
         }
         if ((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_VISIBILITY) == 0) {
             if (updatedChannel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 29fa754..66fb976 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -595,7 +595,7 @@
                     if (RULE_INSTANCE_GRACE_PERIOD < (currentTime - rule.creationTime)) {
                         try {
                             mPm.getPackageInfo(rule.component.getPackageName(),
-                                    PackageManager.MATCH_UNINSTALLED_PACKAGES);
+                                    PackageManager.MATCH_ANY_USER);
                         } catch (PackageManager.NameNotFoundException e) {
                             newConfig.automaticRules.removeAt(i);
                         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e31df52..dd410e2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -59,11 +59,13 @@
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
 import static android.content.pm.PackageManager.MATCH_ALL;
+import static android.content.pm.PackageManager.MATCH_ANY_USER;
 import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
 import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
 import static android.content.pm.PackageManager.MATCH_FACTORY_ONLY;
+import static android.content.pm.PackageManager.MATCH_KNOWN_PACKAGES;
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
 import static android.content.pm.PackageManager.MOVE_FAILED_DEVICE_ADMIN;
@@ -100,6 +102,7 @@
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
@@ -774,13 +777,11 @@
 
     private int mIntentFilterVerificationToken = 0;
 
-    /** Component that knows whether or not an ephemeral application exists */
-    final ComponentName mEphemeralResolverComponent;
     /** The service connection to the ephemeral resolver */
     final EphemeralResolverConnection mEphemeralResolverConnection;
 
     /** Component used to install ephemeral applications */
-    final ComponentName mEphemeralInstallerComponent;
+    ComponentName mEphemeralInstallerComponent;
     final ActivityInfo mEphemeralInstallerActivity = new ActivityInfo();
     final ResolveInfo mEphemeralInstallerInfo = new ResolveInfo();
 
@@ -2740,32 +2741,22 @@
             mInstallerService = new PackageInstallerService(context, this);
 
             final ComponentName ephemeralResolverComponent = getEphemeralResolverLPr();
-            final ComponentName ephemeralInstallerComponent = getEphemeralInstallerLPr();
-            // both the installer and resolver must be present to enable ephemeral
-            if (ephemeralInstallerComponent != null && ephemeralResolverComponent != null) {
+            if (ephemeralResolverComponent != null) {
                 if (DEBUG_EPHEMERAL) {
-                    Slog.i(TAG, "Ephemeral activated; resolver: " + ephemeralResolverComponent
-                            + " installer:" + ephemeralInstallerComponent);
+                    Slog.i(TAG, "Ephemeral resolver: " + ephemeralResolverComponent);
                 }
-                mEphemeralResolverComponent = ephemeralResolverComponent;
-                mEphemeralInstallerComponent = ephemeralInstallerComponent;
-                setUpEphemeralInstallerActivityLP(mEphemeralInstallerComponent);
                 mEphemeralResolverConnection =
-                        new EphemeralResolverConnection(mContext, mEphemeralResolverComponent);
+                        new EphemeralResolverConnection(mContext, ephemeralResolverComponent);
             } else {
-                if (DEBUG_EPHEMERAL) {
-                    final String missingComponent =
-                            (ephemeralResolverComponent == null)
-                            ? (ephemeralInstallerComponent == null)
-                                    ? "resolver and installer"
-                                    : "resolver"
-                            : "installer";
-                    Slog.i(TAG, "Ephemeral deactivated; missing " + missingComponent);
-                }
-                mEphemeralResolverComponent = null;
-                mEphemeralInstallerComponent = null;
                 mEphemeralResolverConnection = null;
             }
+            mEphemeralInstallerComponent = getEphemeralInstallerLPr();
+            if (mEphemeralInstallerComponent != null) {
+                if (DEBUG_EPHEMERAL) {
+                    Slog.i(TAG, "Ephemeral installer: " + mEphemeralInstallerComponent);
+                }
+                setUpEphemeralInstallerActivityLP(mEphemeralInstallerComponent);
+            }
 
             mEphemeralApplicationRegistry = new EphemeralApplicationRegistry(this);
         } // synchronized (mPackages)
@@ -2957,6 +2948,18 @@
                 | (!Build.IS_DEBUGGABLE ? MATCH_SYSTEM_ONLY : 0);
         final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, PACKAGE_MIME_TYPE,
                 resolveFlags, UserHandle.USER_SYSTEM);
+        Iterator<ResolveInfo> iter = matches.iterator();
+        while (iter.hasNext()) {
+            final ResolveInfo rInfo = iter.next();
+            final PackageSetting ps = mSettings.mPackages.get(rInfo.activityInfo.packageName);
+            if (ps != null) {
+                final PermissionsState permissionsState = ps.getPermissionsState();
+                if (permissionsState.hasPermission(Manifest.permission.INSTALL_PACKAGES, 0)) {
+                    continue;
+                }
+            }
+            iter.remove();
+        }
         if (matches.size() == 0) {
             return null;
         } else if (matches.size() == 1) {
@@ -3140,6 +3143,11 @@
                 ? Collections.<String>emptySet() : permissionsState.getPermissions(userId);
         final PackageUserState state = ps.readUserState(userId);
 
+        if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0
+                && ps.isSystem()) {
+            flags |= MATCH_ANY_USER;
+        }
+
         return PackageParser.generatePackageInfo(p, gids, flags,
                 ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId);
     }
@@ -3221,7 +3229,7 @@
             if (p != null) {
                 return generatePackageInfo((PackageSetting)p.mExtras, flags, userId);
             }
-            if (!matchFactoryOnly && (flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
+            if (!matchFactoryOnly && (flags & MATCH_KNOWN_PACKAGES) != 0) {
                 final PackageSetting ps = mSettings.mPackages.get(packageName);
                 return generatePackageInfo(ps, flags, userId);
             }
@@ -3268,7 +3276,7 @@
             if (p != null && p.isMatch(flags)) {
                 return UserHandle.getUid(userId, p.applicationInfo.uid);
             }
-            if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
+            if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
                 final PackageSetting ps = mSettings.mPackages.get(packageName);
                 if (ps != null && ps.isMatch(flags)) {
                     return UserHandle.getUid(userId, ps.appId);
@@ -3292,9 +3300,11 @@
             final PackageParser.Package p = mPackages.get(packageName);
             if (p != null && p.isMatch(flags)) {
                 PackageSetting ps = (PackageSetting) p.mExtras;
+                // TODO: Shouldn't this be checking for package installed state for userId and
+                // return null?
                 return ps.getPermissionsState().computeGids(userId);
             }
-            if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
+            if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
                 final PackageSetting ps = mSettings.mPackages.get(packageName);
                 if (ps != null && ps.isMatch(flags)) {
                     return ps.getPermissionsState().computeGids(userId);
@@ -3418,7 +3428,7 @@
             if ("android".equals(packageName)||"system".equals(packageName)) {
                 return mAndroidApplication;
             }
-            if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
+            if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
                 return generateApplicationInfoFromSettingsLPw(packageName, flags, userId);
             }
         }
@@ -3527,6 +3537,7 @@
      * Update given flags when being used to request {@link PackageInfo}.
      */
     private int updateFlagsForPackage(int flags, int userId, Object cookie) {
+        final boolean isCallerSystemUser = UserHandle.getCallingUserId() == UserHandle.USER_SYSTEM;
         boolean triaged = true;
         if ((flags & (PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS
                 | PackageManager.GET_SERVICES | PackageManager.GET_PROVIDERS)) != 0) {
@@ -3543,6 +3554,18 @@
                 | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
             triaged = false;
         }
+        if ((flags & PackageManager.MATCH_ANY_USER) != 0) {
+            enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false,
+                    "MATCH_ANY_USER flag requires INTERACT_ACROSS_USERS permission at "
+                    + Debug.getCallers(5));
+        } else if ((flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0 && isCallerSystemUser
+                && sUserManager.hasManagedProfile(UserHandle.USER_SYSTEM)) {
+            // If the caller wants all packages and has a restricted profile associated with it,
+            // then match all users. This is to make sure that launchers that need to access work
+            // profile apps don't start breaking. TODO: Remove this hack when launchers stop using
+            // MATCH_UNINSTALLED_PACKAGES to query apps in other profiles. b/31000380
+            flags |= PackageManager.MATCH_ANY_USER;
+        }
         if (DEBUG_TRIAGED_MISSING && (Binder.getCallingUid() == Process.SYSTEM_UID) && !triaged) {
             Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie
                     + " with flags 0x" + Integer.toHexString(flags), new Throwable());
@@ -5019,6 +5042,9 @@
         if (mEphemeralResolverConnection == null) {
             return false;
         }
+        if (mEphemeralInstallerComponent == null) {
+            return false;
+        }
         if (intent.getComponent() != null) {
             return false;
         }
@@ -6296,7 +6322,7 @@
     public ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) {
         if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
         flags = updateFlagsForPackage(flags, userId, null);
-        final boolean listUninstalled = (flags & MATCH_UNINSTALLED_PACKAGES) != 0;
+        final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
         enforceCrossUserPermission(Binder.getCallingUid(), userId,
                 true /* requireFullPermission */, false /* checkShell */,
                 "get installed packages");
@@ -6380,7 +6406,10 @@
             String[] permissions, int flags, int userId) {
         if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
         flags = updateFlagsForPackage(flags, userId, permissions);
-        final boolean listUninstalled = (flags & MATCH_UNINSTALLED_PACKAGES) != 0;
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, false /* checkShell */,
+                "get packages holding permissions");
+        final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
 
         // writer
         synchronized (mPackages) {
@@ -6388,7 +6417,8 @@
             boolean[] tmpBools = new boolean[permissions.length];
             if (listUninstalled) {
                 for (PackageSetting ps : mSettings.mPackages.values()) {
-                    addPackageHoldingPermissions(list, ps, permissions, tmpBools, flags, userId);
+                    addPackageHoldingPermissions(list, ps, permissions, tmpBools, flags,
+                            userId);
                 }
             } else {
                 for (PackageParser.Package pkg : mPackages.values()) {
@@ -6408,7 +6438,7 @@
     public ParceledListSlice<ApplicationInfo> getInstalledApplications(int flags, int userId) {
         if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
         flags = updateFlagsForApplication(flags, userId, null);
-        final boolean listUninstalled = (flags & MATCH_UNINSTALLED_PACKAGES) != 0;
+        final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
 
         // writer
         synchronized (mPackages) {
@@ -6417,11 +6447,16 @@
                 list = new ArrayList<ApplicationInfo>(mSettings.mPackages.size());
                 for (PackageSetting ps : mSettings.mPackages.values()) {
                     ApplicationInfo ai;
+                    int effectiveFlags = flags;
+                    if (ps.isSystem()) {
+                        effectiveFlags |= PackageManager.MATCH_ANY_USER;
+                    }
                     if (ps.pkg != null) {
-                        ai = PackageParser.generateApplicationInfo(ps.pkg, flags,
+                        ai = PackageParser.generateApplicationInfo(ps.pkg, effectiveFlags,
                                 ps.readUserState(userId), userId);
                     } else {
-                        ai = generateApplicationInfoFromSettingsLPw(ps.name, flags, userId);
+                        ai = generateApplicationInfoFromSettingsLPw(ps.name, effectiveFlags,
+                                userId);
                     }
                     if (ai != null) {
                         list.add(ai);
@@ -9051,6 +9086,13 @@
                 PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i);
                 PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name);
                 final String curPackageName = cur == null ? null : cur.info.packageName;
+                // Dont allow ephemeral apps to define new permission groups.
+                if (pkg.applicationInfo.isEphemeralApp()) {
+                    Slog.w(TAG, "Permission group " + pg.info.name + " from package "
+                            + pg.info.packageName
+                            + " ignored: ephemeral apps cannot define new permission groups.");
+                    continue;
+                }
                 final boolean isPackageUpdate = pg.info.packageName.equals(curPackageName);
                 if (cur == null || isPackageUpdate) {
                     mPermissionGroups.put(pg.info.name, pg);
@@ -9089,6 +9131,14 @@
             for (i=0; i<N; i++) {
                 PackageParser.Permission p = pkg.permissions.get(i);
 
+                // Dont allow ephemeral apps to define new permissions.
+                if (pkg.applicationInfo.isEphemeralApp()) {
+                    Slog.w(TAG, "Permission " + p.info.name + " from package "
+                            + p.info.packageName
+                            + " ignored: ephemeral apps cannot define new permissions.");
+                    continue;
+                }
+
                 // Assume by default that we did not install this permission into the system.
                 p.info.flags &= ~PermissionInfo.FLAG_INSTALLED;
 
@@ -9588,11 +9638,21 @@
     }
 
     private void setUpEphemeralInstallerActivityLP(ComponentName installerComponent) {
-        final PackageParser.Package pkg = mPackages.get(installerComponent.getPackageName());
+        if (installerComponent == null) {
+            if (DEBUG_EPHEMERAL) {
+                Slog.d(TAG, "Clear ephemeral installer activity");
+            }
+            mEphemeralInstallerActivity.applicationInfo = null;
+            return;
+        }
 
+        if (DEBUG_EPHEMERAL) {
+            Slog.d(TAG, "Set ephemeral installer activity: " + installerComponent);
+        }
+        final PackageParser.Package pkg = mPackages.get(installerComponent.getPackageName());
         // Set up information for ephemeral installer activity
         mEphemeralInstallerActivity.applicationInfo = pkg.applicationInfo;
-        mEphemeralInstallerActivity.name = mEphemeralInstallerComponent.getClassName();
+        mEphemeralInstallerActivity.name = installerComponent.getClassName();
         mEphemeralInstallerActivity.packageName = pkg.applicationInfo.packageName;
         mEphemeralInstallerActivity.processName = pkg.applicationInfo.packageName;
         mEphemeralInstallerActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
@@ -9607,10 +9667,6 @@
         mEphemeralInstallerInfo.isDefault = true;
         mEphemeralInstallerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
                 | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
-
-        if (DEBUG_EPHEMERAL) {
-            Slog.d(TAG, "Set ephemeral installer activity: " + mEphemeralInstallerComponent);
-        }
     }
 
     private static String calculateBundledApkRoot(final String codePathString) {
@@ -10522,18 +10578,21 @@
             BasePermission bp, PermissionsState origPermissions) {
         boolean privilegedPermission = (bp.protectionLevel
                 & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0;
-        boolean controlPrivappPermissions = RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS;
+        boolean privappPermissionsDisable =
+                RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE;
         boolean platformPermission = PLATFORM_PACKAGE_NAME.equals(bp.sourcePackage);
         boolean platformPackage = PLATFORM_PACKAGE_NAME.equals(pkg.packageName);
-        if (controlPrivappPermissions && privilegedPermission && pkg.isPrivilegedApp()
+        if (!privappPermissionsDisable && privilegedPermission && pkg.isPrivilegedApp()
                 && !platformPackage && platformPermission) {
             ArraySet<String> wlPermissions = SystemConfig.getInstance()
                     .getPrivAppPermissions(pkg.packageName);
             boolean whitelisted = wlPermissions != null && wlPermissions.contains(perm);
             if (!whitelisted) {
-                // Log for now. TODO Enforce permissions
                 Slog.w(TAG, "Privileged permission " + perm + " for package "
                         + pkg.packageName + " - not in privapp-permissions whitelist");
+                if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) {
+                    return false;
+                }
             }
         }
         boolean allowed = (compareSignatures(
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 834d343..7938a12 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -51,9 +51,11 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.PrintWriterPrinter;
 import com.android.internal.content.PackageHelper;
 import com.android.internal.util.SizedInputStream;
+import com.android.server.SystemConfig;
 
 import dalvik.system.DexFile;
 
@@ -135,6 +137,8 @@
                     return runSuspend(false);
                 case "set-home-activity":
                     return runSetHomeActivity();
+                case "get-privapp-permissions":
+                    return runGetPrivappPermissions();
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -610,7 +614,7 @@
                         showUid = true;
                         break;
                     case "-u":
-                        getFlags |= PackageManager.GET_UNINSTALLED_PACKAGES;
+                        getFlags |= PackageManager.MATCH_UNINSTALLED_PACKAGES;
                         break;
                     case "-3":
                         listThirdParty = true;
@@ -1164,6 +1168,18 @@
         }
     }
 
+    private int runGetPrivappPermissions() {
+        final String pkg = getNextArg();
+        if (pkg == null) {
+            System.err.println("Error: no package specified.");
+            return 1;
+        }
+        ArraySet<String> privAppPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg);
+        getOutPrintWriter().println(privAppPermissions == null
+                ? "{}" : privAppPermissions.toString());
+        return 0;
+    }
+
     private static String checkAbiArgument(String abi) {
         if (TextUtils.isEmpty(abi)) {
             throw new IllegalArgumentException("Missing ABI argument");
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index d558b07..2eb0778 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -259,6 +259,11 @@
         for (int i = mShortcuts.size() - 1; i >= 0; i--) {
             final ShortcutInfo si = mShortcuts.valueAt(i);
 
+            if (si.isFloating()) {
+                si.setRank(0);
+                si.setActivity(null);
+            }
+
             if (si.isAlive()) continue;
 
             if (removeList == null) {
@@ -288,6 +293,7 @@
                 si.setTimestamp(now);
                 si.clearFlags(ShortcutInfo.FLAG_DYNAMIC);
                 si.setRank(0); // It may still be pinned, so clear the rank.
+                si.setActivity(null);
             }
         }
         if (changed) {
@@ -355,6 +361,7 @@
         if (oldShortcut.isPinned()) {
 
             oldShortcut.setRank(0);
+            oldShortcut.setActivity(null);
             oldShortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_MANIFEST);
             if (disable) {
                 oldShortcut.addFlags(ShortcutInfo.FLAG_DISABLED);
@@ -595,6 +602,10 @@
 
         for (int i = mShortcuts.size() - 1; i >= 0; i--) {
             final ShortcutInfo si = mShortcuts.valueAt(i);
+
+            if (si.isFloating()) {
+                continue; // Ignore floating shortcuts, which are not tied to any activities.
+            }
             final ComponentName activity = si.getActivity();
 
             if (checked.contains(activity)) {
@@ -1356,6 +1367,10 @@
                     case TAG_SHORTCUT:
                         final ShortcutInfo si = parseShortcut(parser, packageName,
                                 shortcutUser.getUserId());
+                        // Floating shortcut used to have target activities, but not anymore.
+                        if (si.isFloating()) { // Not really needed by just in case.
+                            si.setActivity(null);
+                        }
 
                         // Don't use addShortcut(), we don't need to save the icon.
                         ret.mShortcuts.put(si.getId(), si);
@@ -1462,7 +1477,6 @@
             intents.clear();
             intents.add(intentLegacy);
         }
-
         return new ShortcutInfo(
                 userId, id, packageName, activityComponent, /* icon =*/ null,
                 title, titleResId, titleResName, text, textResId, textResName,
@@ -1553,12 +1567,17 @@
                 Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
                         + " is both dynamic and manifest at the same time.");
             }
-            if (si.getActivity() == null) {
+            if (!si.isFloating() && si.getActivity() == null) {
                 failed = true;
                 Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
-                        + " has null activity.");
+                        + " is not floating, but has null activity.");
             }
-            if ((si.isDynamic() || si.isManifestShortcut()) && !si.isEnabled()) {
+            if (si.isFloating() && si.getActivity() != null) {
+                failed = true;
+                Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
+                        + " is floating, but has non-null activity.");
+            }
+            if (!si.isFloating() && !si.isEnabled()) {
                 failed = true;
                 Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
                         + " is not floating, but is disabled.");
@@ -1581,7 +1600,7 @@
         }
 
         if (failed) {
-            throw new IllegalStateException("See logcat for errors");
+            mShortcutUser.mService.verifyError();
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
index 4de15de..e5a2f5a 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
@@ -23,7 +23,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.backup.BackupUtils;
 
-import libcore.io.Base64;
 import libcore.util.HexEncoding;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -33,6 +32,7 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Base64;
 
 /**
  * Package information used by {@link android.content.pm.ShortcutManager} for backup / restore.
@@ -161,7 +161,8 @@
 
         for (int i = 0; i < mSigHashes.size(); i++) {
             out.startTag(null, TAG_SIGNATURE);
-            ShortcutService.writeAttr(out, ATTR_SIGNATURE_HASH, Base64.encode(mSigHashes.get(i)));
+            final String encoded = Base64.getEncoder().encodeToString(mSigHashes.get(i));
+            ShortcutService.writeAttr(out, ATTR_SIGNATURE_HASH, encoded);
             out.endTag(null, TAG_SIGNATURE);
         }
         out.endTag(null, TAG_ROOT);
@@ -196,7 +197,9 @@
                     case TAG_SIGNATURE: {
                         final String hash = ShortcutService.parseStringAttribute(
                                 parser, ATTR_SIGNATURE_HASH);
-                        hashes.add(Base64.decode(hash.getBytes()));
+                        // Throws IllegalArgumentException if hash is invalid base64 data
+                        final byte[] decoded = Base64.getDecoder().decode(hash);
+                        hashes.add(decoded);
                         continue;
                     }
                 }
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
index 1f195a7..e59d69f 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
@@ -106,27 +106,31 @@
             }
             return; // Not installed, no need to restore yet.
         }
+        boolean blockRestore = false;
         if (!mPackageInfo.hasSignatures()) {
             s.wtf("Attempted to restore package " + mPackageName + ", user=" + mPackageUserId
                     + " but signatures not found in the restore data.");
+            blockRestore = true;
+        }
+        if (!blockRestore) {
+            final PackageInfo pi = s.getPackageInfoWithSignatures(mPackageName, mPackageUserId);
+            if (!mPackageInfo.canRestoreTo(s, pi)) {
+                // Package is now installed, but can't restore.  Let the subclass do the cleanup.
+                blockRestore = true;
+            }
+        }
+        if (blockRestore) {
             onRestoreBlocked();
-            return;
+        } else {
+            if (ShortcutService.DEBUG) {
+                Slog.d(TAG, String.format("Restored package: %s/%d on user %d", mPackageName,
+                        mPackageUserId, getOwnerUserId()));
+            }
+
+            onRestored();
         }
 
-        final PackageInfo pi = s.getPackageInfoWithSignatures(mPackageName, mPackageUserId);
-        if (!mPackageInfo.canRestoreTo(s, pi)) {
-            // Package is now installed, but can't restore.  Let the subclass do the cleanup.
-            onRestoreBlocked();
-            return;
-        }
-        if (ShortcutService.DEBUG) {
-            Slog.d(TAG, String.format("Restored package: %s/%d on user %d", mPackageName,
-                    mPackageUserId, getOwnerUserId()));
-        }
-
-        onRestored();
-
-        // Now the package is not shadow.
+        // Either way, it's no longer a shadow.
         mPackageInfo.setShadow(false);
 
         s.scheduleSaveUser(mPackageUserId);
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 7b877f7..c5c1c0c 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -124,6 +124,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
@@ -401,6 +402,9 @@
 
     @VisibleForTesting
     ShortcutService(Context context, Looper looper, boolean onlyForPackageManagerApis) {
+        if (DEBUG) {
+            Binder.LOG_RUNTIME_EXCEPTION = true;
+        }
         mContext = Preconditions.checkNotNull(context);
         LocalServices.addService(ShortcutServiceInternal.class, new LocalService());
         mHandler = new Handler(looper);
@@ -1604,7 +1608,7 @@
         }
 
         if (!forUpdate) {
-            shortcut.enforceMandatoryFields();
+            shortcut.enforceMandatoryFields(/* forPinned= */ false);
             Preconditions.checkArgument(
                     injectIsMainActivity(shortcut.getActivity(), shortcut.getUserId()),
                     "Cannot publish shortcut: " + shortcut.getActivity() + " is not main activity");
@@ -1752,6 +1756,9 @@
 
                 // Note copyNonNullFieldsFrom() does the "updatable with?" check too.
                 target.copyNonNullFieldsFrom(source);
+                if (target.isFloating()) {
+                    target.setActivity(null);
+                }
                 target.setTimestamp(injectCurrentTimeMillis());
 
                 if (replacingIcon) {
@@ -2320,8 +2327,7 @@
                             return false;
                         }
                         if (componentName != null) {
-                            if (si.getActivity() != null
-                                    && !si.getActivity().equals(componentName)) {
+                            if (!Objects.equals(componentName, si.getActivity())) {
                                 return false;
                             }
                         }
@@ -3733,6 +3739,16 @@
         }
     }
 
+    @VisibleForTesting
+    ShortcutLauncher getLauncherShortcutForTest(String packageName, int userId) {
+        synchronized (mLock) {
+            final ShortcutUser user = mUsers.get(userId);
+            if (user == null) return null;
+
+            return user.getAllLaunchersForTest().get(PackageWithUser.of(userId, packageName));
+        }
+    }
+
     /**
      * Control whether {@link #verifyStates} should be performed.  We always perform it during unit
      * tests.
@@ -3761,4 +3777,8 @@
             forEachLoadedUserLocked(u -> u.forAllPackageItems(ShortcutPackageItem::verifyStates));
         }
     }
+
+    void verifyError() {
+        Slog.e(TAG, "See logcat for errors");
+    }
 }
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 5b47b6f..bac7a76 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -63,6 +63,7 @@
 import android.os.ServiceManager;
 import android.os.ShellCallback;
 import android.os.ShellCommand;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.UserManagerInternal;
@@ -110,6 +111,8 @@
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.nio.charset.StandardCharsets;
@@ -149,6 +152,7 @@
     private static final String ATTR_GUEST_TO_REMOVE = "guestToRemove";
     private static final String ATTR_USER_VERSION = "version";
     private static final String ATTR_PROFILE_GROUP_ID = "profileGroupId";
+    private static final String ATTR_PROFILE_BADGE = "profileBadge";
     private static final String ATTR_RESTRICTED_PROFILE_PARENT_ID = "restrictedProfileParentId";
     private static final String ATTR_SEED_ACCOUNT_NAME = "seedAccountName";
     private static final String ATTR_SEED_ACCOUNT_TYPE = "seedAccountType";
@@ -203,7 +207,8 @@
 
     // Maximum number of managed profiles permitted per user is 1. This cannot be increased
     // without first making sure that the rest of the framework is prepared for it.
-    private static final int MAX_MANAGED_PROFILES = 1;
+    @VisibleForTesting
+    static final int MAX_MANAGED_PROFILES = 1;
 
     static final int WRITE_USER_MSG = 1;
     static final int WRITE_USER_DELAY = 2*1000;  // 2 seconds
@@ -232,7 +237,8 @@
      * User-related information that is used for persisting to flash. Only UserInfo is
      * directly exposed to other system apps.
      */
-    private static class UserData {
+    @VisibleForTesting
+    static class UserData {
         // Basic user information and properties
         UserInfo info;
         // Account name used when there is a strong association between a user and an account
@@ -874,6 +880,22 @@
     }
 
     @Override
+    public int getManagedProfileBadge(@UserIdInt int userId) {
+        int callingUserId = UserHandle.getCallingUserId();
+        if (callingUserId != userId && !hasManageUsersPermission()) {
+            if (!isSameProfileGroupNoChecks(callingUserId, userId)) {
+                throw new SecurityException(
+                        "You need MANAGE_USERS permission to: check if specified user a " +
+                        "managed profile outside your profile group");
+            }
+        }
+        synchronized (mUsersLock) {
+            UserInfo userInfo = getUserInfoLU(userId);
+            return userInfo != null ? userInfo.profileBadge : 0;
+        }
+    }
+
+    @Override
     public boolean isManagedProfile(int userId) {
         int callingUserId = UserHandle.getCallingUserId();
         if (callingUserId != userId && !hasManageUsersPermission()) {
@@ -891,17 +913,36 @@
 
     @Override
     public boolean isUserUnlockingOrUnlocked(int userId) {
-        int callingUserId = UserHandle.getCallingUserId();
-        if (callingUserId != userId && !hasManageUsersPermission()) {
-            if (!isSameProfileGroupNoChecks(callingUserId, userId)) {
-                throw new SecurityException(
-                        "You need MANAGE_USERS permission to: check isUserUnlockingOrUnlocked");
-            }
-        }
+        checkManageOrInteractPermIfCallerInOtherProfileGroup(userId, "isUserUnlockingOrUnlocked");
         return mLocalService.isUserUnlockingOrUnlocked(userId);
     }
 
     @Override
+    public boolean isUserUnlocked(int userId) {
+        checkManageOrInteractPermIfCallerInOtherProfileGroup(userId, "isUserUnlocked");
+        return mLocalService.isUserUnlockingOrUnlocked(userId);
+    }
+
+    @Override
+    public boolean isUserRunning(int userId) {
+        checkManageOrInteractPermIfCallerInOtherProfileGroup(userId, "isUserRunning");
+        return mLocalService.isUserRunning(userId);
+    }
+
+    private void checkManageOrInteractPermIfCallerInOtherProfileGroup(int userId, String name) {
+        int callingUserId = UserHandle.getCallingUserId();
+        if (callingUserId == userId || isSameProfileGroupNoChecks(callingUserId, userId) ||
+                hasManageUsersPermission()) {
+            return;
+        }
+        if (ActivityManager.checkComponentPermission(Manifest.permission.INTERACT_ACROSS_USERS,
+                Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("You need INTERACT_ACROSS_USERS or MANAGE_USERS permission "
+                    + "to: check " + name);
+        }
+    }
+
+    @Override
     public boolean isDemoUser(int userId) {
         int callingUserId = UserHandle.getCallingUserId();
         if (callingUserId != userId && !hasManageUsersPermission()) {
@@ -1464,7 +1505,7 @@
         // Limit number of managed profiles that can be created
         final int managedProfilesCount = getProfiles(userId, true).size() - 1;
         final int profilesRemovedCount = managedProfilesCount > 0 && allowedToRemoveOne ? 1 : 0;
-        if (managedProfilesCount - profilesRemovedCount >= MAX_MANAGED_PROFILES) {
+        if (managedProfilesCount - profilesRemovedCount >= getMaxManagedProfiles()) {
             return false;
         }
         synchronized(mUsersLock) {
@@ -1859,13 +1900,6 @@
         }
     }
 
-    /*
-     * Writes the user file in this format:
-     *
-     * <user flags="20039023" id="0">
-     *   <name>Primary</name>
-     * </user>
-     */
     private void writeUserLP(UserData userData) {
         if (DBG) {
             debug("writeUserLP " + userData);
@@ -1875,78 +1909,7 @@
         try {
             fos = userFile.startWrite();
             final BufferedOutputStream bos = new BufferedOutputStream(fos);
-
-            // XmlSerializer serializer = XmlUtils.serializerInstance();
-            final XmlSerializer serializer = new FastXmlSerializer();
-            serializer.setOutput(bos, StandardCharsets.UTF_8.name());
-            serializer.startDocument(null, true);
-            serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
-
-            final UserInfo userInfo = userData.info;
-            serializer.startTag(null, TAG_USER);
-            serializer.attribute(null, ATTR_ID, Integer.toString(userInfo.id));
-            serializer.attribute(null, ATTR_SERIAL_NO, Integer.toString(userInfo.serialNumber));
-            serializer.attribute(null, ATTR_FLAGS, Integer.toString(userInfo.flags));
-            serializer.attribute(null, ATTR_CREATION_TIME, Long.toString(userInfo.creationTime));
-            serializer.attribute(null, ATTR_LAST_LOGGED_IN_TIME,
-                    Long.toString(userInfo.lastLoggedInTime));
-            if (userInfo.lastLoggedInFingerprint != null) {
-                serializer.attribute(null, ATTR_LAST_LOGGED_IN_FINGERPRINT,
-                        userInfo.lastLoggedInFingerprint);
-            }
-            if (userInfo.iconPath != null) {
-                serializer.attribute(null,  ATTR_ICON_PATH, userInfo.iconPath);
-            }
-            if (userInfo.partial) {
-                serializer.attribute(null, ATTR_PARTIAL, "true");
-            }
-            if (userInfo.guestToRemove) {
-                serializer.attribute(null, ATTR_GUEST_TO_REMOVE, "true");
-            }
-            if (userInfo.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID) {
-                serializer.attribute(null, ATTR_PROFILE_GROUP_ID,
-                        Integer.toString(userInfo.profileGroupId));
-            }
-            if (userInfo.restrictedProfileParentId != UserInfo.NO_PROFILE_GROUP_ID) {
-                serializer.attribute(null, ATTR_RESTRICTED_PROFILE_PARENT_ID,
-                        Integer.toString(userInfo.restrictedProfileParentId));
-            }
-            // Write seed data
-            if (userData.persistSeedData) {
-                if (userData.seedAccountName != null) {
-                    serializer.attribute(null, ATTR_SEED_ACCOUNT_NAME, userData.seedAccountName);
-                }
-                if (userData.seedAccountType != null) {
-                    serializer.attribute(null, ATTR_SEED_ACCOUNT_TYPE, userData.seedAccountType);
-                }
-            }
-            if (userInfo.name != null) {
-                serializer.startTag(null, TAG_NAME);
-                serializer.text(userInfo.name);
-                serializer.endTag(null, TAG_NAME);
-            }
-            synchronized (mRestrictionsLock) {
-                UserRestrictionsUtils.writeRestrictions(serializer,
-                        mBaseUserRestrictions.get(userInfo.id), TAG_RESTRICTIONS);
-                UserRestrictionsUtils.writeRestrictions(serializer,
-                        mDevicePolicyLocalUserRestrictions.get(userInfo.id),
-                        TAG_DEVICE_POLICY_RESTRICTIONS);
-            }
-
-            if (userData.account != null) {
-                serializer.startTag(null, TAG_ACCOUNT);
-                serializer.text(userData.account);
-                serializer.endTag(null, TAG_ACCOUNT);
-            }
-
-            if (userData.persistSeedData && userData.seedAccountOptions != null) {
-                serializer.startTag(null, TAG_SEED_ACCOUNT_OPTIONS);
-                userData.seedAccountOptions.saveToXml(serializer);
-                serializer.endTag(null, TAG_SEED_ACCOUNT_OPTIONS);
-            }
-            serializer.endTag(null, TAG_USER);
-
-            serializer.endDocument();
+            writeUserLP(userData, bos);
             userFile.finishWrite(fos);
         } catch (Exception ioe) {
             Slog.e(LOG_TAG, "Error writing user info " + userData.info.id, ioe);
@@ -1955,6 +1918,92 @@
     }
 
     /*
+     * Writes the user file in this format:
+     *
+     * <user flags="20039023" id="0">
+     *   <name>Primary</name>
+     * </user>
+     */
+    @VisibleForTesting
+    void writeUserLP(UserData userData, OutputStream os)
+            throws IOException, XmlPullParserException {
+        // XmlSerializer serializer = XmlUtils.serializerInstance();
+        final XmlSerializer serializer = new FastXmlSerializer();
+        serializer.setOutput(os, StandardCharsets.UTF_8.name());
+        serializer.startDocument(null, true);
+        serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+
+        final UserInfo userInfo = userData.info;
+        serializer.startTag(null, TAG_USER);
+        serializer.attribute(null, ATTR_ID, Integer.toString(userInfo.id));
+        serializer.attribute(null, ATTR_SERIAL_NO, Integer.toString(userInfo.serialNumber));
+        serializer.attribute(null, ATTR_FLAGS, Integer.toString(userInfo.flags));
+        serializer.attribute(null, ATTR_CREATION_TIME, Long.toString(userInfo.creationTime));
+        serializer.attribute(null, ATTR_LAST_LOGGED_IN_TIME,
+                Long.toString(userInfo.lastLoggedInTime));
+        if (userInfo.lastLoggedInFingerprint != null) {
+            serializer.attribute(null, ATTR_LAST_LOGGED_IN_FINGERPRINT,
+                    userInfo.lastLoggedInFingerprint);
+        }
+        if (userInfo.iconPath != null) {
+            serializer.attribute(null,  ATTR_ICON_PATH, userInfo.iconPath);
+        }
+        if (userInfo.partial) {
+            serializer.attribute(null, ATTR_PARTIAL, "true");
+        }
+        if (userInfo.guestToRemove) {
+            serializer.attribute(null, ATTR_GUEST_TO_REMOVE, "true");
+        }
+        if (userInfo.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID) {
+            serializer.attribute(null, ATTR_PROFILE_GROUP_ID,
+                    Integer.toString(userInfo.profileGroupId));
+        }
+        serializer.attribute(null, ATTR_PROFILE_BADGE,
+                Integer.toString(userInfo.profileBadge));
+        if (userInfo.restrictedProfileParentId != UserInfo.NO_PROFILE_GROUP_ID) {
+            serializer.attribute(null, ATTR_RESTRICTED_PROFILE_PARENT_ID,
+                    Integer.toString(userInfo.restrictedProfileParentId));
+        }
+        // Write seed data
+        if (userData.persistSeedData) {
+            if (userData.seedAccountName != null) {
+                serializer.attribute(null, ATTR_SEED_ACCOUNT_NAME, userData.seedAccountName);
+            }
+            if (userData.seedAccountType != null) {
+                serializer.attribute(null, ATTR_SEED_ACCOUNT_TYPE, userData.seedAccountType);
+            }
+        }
+        if (userInfo.name != null) {
+            serializer.startTag(null, TAG_NAME);
+            serializer.text(userInfo.name);
+            serializer.endTag(null, TAG_NAME);
+        }
+        synchronized (mRestrictionsLock) {
+            UserRestrictionsUtils.writeRestrictions(serializer,
+                    mBaseUserRestrictions.get(userInfo.id), TAG_RESTRICTIONS);
+            UserRestrictionsUtils.writeRestrictions(serializer,
+                    mDevicePolicyLocalUserRestrictions.get(userInfo.id),
+                    TAG_DEVICE_POLICY_RESTRICTIONS);
+        }
+
+        if (userData.account != null) {
+            serializer.startTag(null, TAG_ACCOUNT);
+            serializer.text(userData.account);
+            serializer.endTag(null, TAG_ACCOUNT);
+        }
+
+        if (userData.persistSeedData && userData.seedAccountOptions != null) {
+            serializer.startTag(null, TAG_SEED_ACCOUNT_OPTIONS);
+            userData.seedAccountOptions.saveToXml(serializer);
+            serializer.endTag(null, TAG_SEED_ACCOUNT_OPTIONS);
+        }
+
+        serializer.endTag(null, TAG_USER);
+
+        serializer.endDocument();
+    }
+
+    /*
      * Writes the user list file in this format:
      *
      * <users nextSerialNumber="3">
@@ -2020,6 +2069,25 @@
     }
 
     private UserData readUserLP(int id) {
+        FileInputStream fis = null;
+        try {
+            AtomicFile userFile =
+                    new AtomicFile(new File(mUsersDir, Integer.toString(id) + XML_SUFFIX));
+            fis = userFile.openRead();
+            return readUserLP(id, fis);
+        } catch (IOException ioe) {
+            Slog.e(LOG_TAG, "Error reading user list");
+        } catch (XmlPullParserException pe) {
+            Slog.e(LOG_TAG, "Error reading user list");
+        } finally {
+            IoUtils.closeQuietly(fis);
+        }
+        return null;
+    }
+
+    @VisibleForTesting
+    UserData readUserLP(int id, InputStream is) throws IOException,
+            XmlPullParserException {
         int flags = 0;
         int serialNumber = id;
         String name = null;
@@ -2029,6 +2097,7 @@
         long lastLoggedInTime = 0L;
         String lastLoggedInFingerprint = null;
         int profileGroupId = UserInfo.NO_PROFILE_GROUP_ID;
+        int profileBadge = 0;
         int restrictedProfileParentId = UserInfo.NO_PROFILE_GROUP_ID;
         boolean partial = false;
         boolean guestToRemove = false;
@@ -2039,120 +2108,106 @@
         Bundle baseRestrictions = new Bundle();
         Bundle localRestrictions = new Bundle();
 
-        FileInputStream fis = null;
-        try {
-            AtomicFile userFile =
-                    new AtomicFile(new File(mUsersDir, Integer.toString(id) + XML_SUFFIX));
-            fis = userFile.openRead();
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(fis, StandardCharsets.UTF_8.name());
-            int type;
-            while ((type = parser.next()) != XmlPullParser.START_TAG
-                    && type != XmlPullParser.END_DOCUMENT) {
-                // Skip
-            }
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(is, StandardCharsets.UTF_8.name());
+        int type;
+        while ((type = parser.next()) != XmlPullParser.START_TAG
+                && type != XmlPullParser.END_DOCUMENT) {
+            // Skip
+        }
 
-            if (type != XmlPullParser.START_TAG) {
-                Slog.e(LOG_TAG, "Unable to read user " + id);
+        if (type != XmlPullParser.START_TAG) {
+            Slog.e(LOG_TAG, "Unable to read user " + id);
+            return null;
+        }
+
+        if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_USER)) {
+            int storedId = readIntAttribute(parser, ATTR_ID, -1);
+            if (storedId != id) {
+                Slog.e(LOG_TAG, "User id does not match the file name");
                 return null;
             }
+            serialNumber = readIntAttribute(parser, ATTR_SERIAL_NO, id);
+            flags = readIntAttribute(parser, ATTR_FLAGS, 0);
+            iconPath = parser.getAttributeValue(null, ATTR_ICON_PATH);
+            creationTime = readLongAttribute(parser, ATTR_CREATION_TIME, 0);
+            lastLoggedInTime = readLongAttribute(parser, ATTR_LAST_LOGGED_IN_TIME, 0);
+            lastLoggedInFingerprint = parser.getAttributeValue(null,
+                    ATTR_LAST_LOGGED_IN_FINGERPRINT);
+            profileGroupId = readIntAttribute(parser, ATTR_PROFILE_GROUP_ID,
+                    UserInfo.NO_PROFILE_GROUP_ID);
+            profileBadge = readIntAttribute(parser, ATTR_PROFILE_BADGE, 0);
+            restrictedProfileParentId = readIntAttribute(parser,
+                    ATTR_RESTRICTED_PROFILE_PARENT_ID, UserInfo.NO_PROFILE_GROUP_ID);
+            String valueString = parser.getAttributeValue(null, ATTR_PARTIAL);
+            if ("true".equals(valueString)) {
+                partial = true;
+            }
+            valueString = parser.getAttributeValue(null, ATTR_GUEST_TO_REMOVE);
+            if ("true".equals(valueString)) {
+                guestToRemove = true;
+            }
 
-            if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_USER)) {
-                int storedId = readIntAttribute(parser, ATTR_ID, -1);
-                if (storedId != id) {
-                    Slog.e(LOG_TAG, "User id does not match the file name");
-                    return null;
-                }
-                serialNumber = readIntAttribute(parser, ATTR_SERIAL_NO, id);
-                flags = readIntAttribute(parser, ATTR_FLAGS, 0);
-                iconPath = parser.getAttributeValue(null, ATTR_ICON_PATH);
-                creationTime = readLongAttribute(parser, ATTR_CREATION_TIME, 0);
-                lastLoggedInTime = readLongAttribute(parser, ATTR_LAST_LOGGED_IN_TIME, 0);
-                lastLoggedInFingerprint = parser.getAttributeValue(null,
-                        ATTR_LAST_LOGGED_IN_FINGERPRINT);
-                profileGroupId = readIntAttribute(parser, ATTR_PROFILE_GROUP_ID,
-                        UserInfo.NO_PROFILE_GROUP_ID);
-                restrictedProfileParentId = readIntAttribute(parser,
-                        ATTR_RESTRICTED_PROFILE_PARENT_ID, UserInfo.NO_PROFILE_GROUP_ID);
-                String valueString = parser.getAttributeValue(null, ATTR_PARTIAL);
-                if ("true".equals(valueString)) {
-                    partial = true;
-                }
-                valueString = parser.getAttributeValue(null, ATTR_GUEST_TO_REMOVE);
-                if ("true".equals(valueString)) {
-                    guestToRemove = true;
-                }
+            seedAccountName = parser.getAttributeValue(null, ATTR_SEED_ACCOUNT_NAME);
+            seedAccountType = parser.getAttributeValue(null, ATTR_SEED_ACCOUNT_TYPE);
+            if (seedAccountName != null || seedAccountType != null) {
+                persistSeedData = true;
+            }
 
-                seedAccountName = parser.getAttributeValue(null, ATTR_SEED_ACCOUNT_NAME);
-                seedAccountType = parser.getAttributeValue(null, ATTR_SEED_ACCOUNT_TYPE);
-                if (seedAccountName != null || seedAccountType != null) {
+            int outerDepth = parser.getDepth();
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                    continue;
+                }
+                String tag = parser.getName();
+                if (TAG_NAME.equals(tag)) {
+                    type = parser.next();
+                    if (type == XmlPullParser.TEXT) {
+                        name = parser.getText();
+                    }
+                } else if (TAG_RESTRICTIONS.equals(tag)) {
+                    UserRestrictionsUtils.readRestrictions(parser, baseRestrictions);
+                } else if (TAG_DEVICE_POLICY_RESTRICTIONS.equals(tag)) {
+                    UserRestrictionsUtils.readRestrictions(parser, localRestrictions);
+                } else if (TAG_ACCOUNT.equals(tag)) {
+                    type = parser.next();
+                    if (type == XmlPullParser.TEXT) {
+                        account = parser.getText();
+                    }
+                } else if (TAG_SEED_ACCOUNT_OPTIONS.equals(tag)) {
+                    seedAccountOptions = PersistableBundle.restoreFromXml(parser);
                     persistSeedData = true;
                 }
-
-                int outerDepth = parser.getDepth();
-                while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                       && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-                    if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                        continue;
-                    }
-                    String tag = parser.getName();
-                    if (TAG_NAME.equals(tag)) {
-                        type = parser.next();
-                        if (type == XmlPullParser.TEXT) {
-                            name = parser.getText();
-                        }
-                    } else if (TAG_RESTRICTIONS.equals(tag)) {
-                        UserRestrictionsUtils.readRestrictions(parser, baseRestrictions);
-                    } else if (TAG_DEVICE_POLICY_RESTRICTIONS.equals(tag)) {
-                        UserRestrictionsUtils.readRestrictions(parser, localRestrictions);
-                    } else if (TAG_ACCOUNT.equals(tag)) {
-                        type = parser.next();
-                        if (type == XmlPullParser.TEXT) {
-                            account = parser.getText();
-                        }
-                    } else if (TAG_SEED_ACCOUNT_OPTIONS.equals(tag)) {
-                        seedAccountOptions = PersistableBundle.restoreFromXml(parser);
-                        persistSeedData = true;
-                    }
-                }
-            }
-
-            // Create the UserInfo object that gets passed around
-            UserInfo userInfo = new UserInfo(id, name, iconPath, flags);
-            userInfo.serialNumber = serialNumber;
-            userInfo.creationTime = creationTime;
-            userInfo.lastLoggedInTime = lastLoggedInTime;
-            userInfo.lastLoggedInFingerprint = lastLoggedInFingerprint;
-            userInfo.partial = partial;
-            userInfo.guestToRemove = guestToRemove;
-            userInfo.profileGroupId = profileGroupId;
-            userInfo.restrictedProfileParentId = restrictedProfileParentId;
-
-            // Create the UserData object that's internal to this class
-            UserData userData = new UserData();
-            userData.info = userInfo;
-            userData.account = account;
-            userData.seedAccountName = seedAccountName;
-            userData.seedAccountType = seedAccountType;
-            userData.persistSeedData = persistSeedData;
-            userData.seedAccountOptions = seedAccountOptions;
-
-            synchronized (mRestrictionsLock) {
-                mBaseUserRestrictions.put(id, baseRestrictions);
-                mDevicePolicyLocalUserRestrictions.put(id, localRestrictions);
-            }
-            return userData;
-        } catch (IOException ioe) {
-        } catch (XmlPullParserException pe) {
-        } finally {
-            if (fis != null) {
-                try {
-                    fis.close();
-                } catch (IOException e) {
-                }
             }
         }
-        return null;
+
+        // Create the UserInfo object that gets passed around
+        UserInfo userInfo = new UserInfo(id, name, iconPath, flags);
+        userInfo.serialNumber = serialNumber;
+        userInfo.creationTime = creationTime;
+        userInfo.lastLoggedInTime = lastLoggedInTime;
+        userInfo.lastLoggedInFingerprint = lastLoggedInFingerprint;
+        userInfo.partial = partial;
+        userInfo.guestToRemove = guestToRemove;
+        userInfo.profileGroupId = profileGroupId;
+        userInfo.profileBadge = profileBadge;
+        userInfo.restrictedProfileParentId = restrictedProfileParentId;
+
+        // Create the UserData object that's internal to this class
+        UserData userData = new UserData();
+        userData.info = userInfo;
+        userData.account = account;
+        userData.seedAccountName = seedAccountName;
+        userData.seedAccountType = seedAccountType;
+        userData.persistSeedData = persistSeedData;
+        userData.seedAccountOptions = seedAccountOptions;
+
+        synchronized (mRestrictionsLock) {
+            mBaseUserRestrictions.put(id, baseRestrictions);
+            mDevicePolicyLocalUserRestrictions.put(id, localRestrictions);
+        }
+        return userData;
     }
 
     private int readIntAttribute(XmlPullParser parser, String attr, int defaultValue) {
@@ -2316,6 +2371,9 @@
                     userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;
                     userInfo.partial = true;
                     userInfo.lastLoggedInFingerprint = Build.FINGERPRINT;
+                    if (isManagedProfile && parentId != UserHandle.USER_NULL) {
+                        userInfo.profileBadge = getFreeProfileBadgeLU(parentId);
+                    }
                     userData = new UserData();
                     userData.info = userInfo;
                     mUsers.put(userId, userData);
@@ -2677,7 +2735,7 @@
     public Bundle getApplicationRestrictionsForUser(String packageName, int userId) {
         if (UserHandle.getCallingUserId() != userId
                 || !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) {
-            checkSystemOrRoot("get application restrictions for other users/apps");
+            checkSystemOrRoot("get application restrictions for other user/app " + packageName);
         }
         synchronized (mPackagesLock) {
             // Read the restrictions from XML
@@ -2712,7 +2770,7 @@
         long ident = Binder.clearCallingIdentity();
         try {
             return mContext.getPackageManager().getApplicationInfo(packageName,
-                    PackageManager.MATCH_UNINSTALLED_PACKAGES).uid;
+                    PackageManager.MATCH_ANY_USER).uid;
         } catch (NameNotFoundException nnfe) {
             return -1;
         } finally {
@@ -3602,6 +3660,14 @@
                         || (state == UserState.STATE_RUNNING_UNLOCKED);
             }
         }
+
+        @Override
+        public boolean isUserUnlocked(int userId) {
+            synchronized (mUserStates) {
+                int state = mUserStates.get(userId, -1);
+                return state == UserState.STATE_RUNNING_UNLOCKED;
+            }
+        }
     }
 
     /* Remove all the users except of the system one. */
@@ -3643,4 +3709,58 @@
         Log.d(LOG_TAG, message +
                 (DBG_WITH_STACKTRACE ? " called at\n" + Debug.getCallers(10, "  ") : ""));
     }
+
+    @VisibleForTesting
+    static int getMaxManagedProfiles() {
+        // Allow overriding max managed profiles on debuggable builds for testing
+        // of multiple profiles.
+        if (!Build.IS_DEBUGGABLE) {
+            return MAX_MANAGED_PROFILES;
+        } else {
+            return SystemProperties.getInt("persist.sys.max_profiles",
+                    MAX_MANAGED_PROFILES);
+        }
+    }
+
+    @VisibleForTesting
+    int getFreeProfileBadgeLU(int parentUserId) {
+        int maxManagedProfiles = getMaxManagedProfiles();
+        boolean[] usedBadges = new boolean[maxManagedProfiles];
+        final int userSize = mUsers.size();
+        for (int i = 0; i < userSize; i++) {
+            UserInfo ui = mUsers.valueAt(i).info;
+            // Check which badge indexes are already used by this profile group.
+            if (ui.isManagedProfile()
+                    && ui.profileGroupId == parentUserId
+                    && !mRemovingUserIds.get(ui.id)
+                    && ui.profileBadge < maxManagedProfiles) {
+                usedBadges[ui.profileBadge] = true;
+            }
+        }
+        for (int i = 0; i < maxManagedProfiles; i++) {
+            if (!usedBadges[i]) {
+                return i;
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * Checks if the given user has a managed profile associated with it.
+     * @param userId The parent user
+     * @return
+     */
+    boolean hasManagedProfile(int userId) {
+        synchronized (mUsersLock) {
+            UserInfo userInfo = getUserInfoLU(userId);
+            final int userSize = mUsers.size();
+            for (int i = 0; i < userSize; i++) {
+                UserInfo profile = mUsers.valueAt(i).info;
+                if (userId != profile.id && isProfileOf(userInfo, profile)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 9fe0922..7ec3c19 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -71,6 +71,7 @@
             UserManager.DISALLOW_SHARE_LOCATION,
             UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
             UserManager.DISALLOW_CONFIG_BLUETOOTH,
+            UserManager.DISALLOW_BLUETOOTH,
             UserManager.DISALLOW_USB_FILE_TRANSFER,
             UserManager.DISALLOW_CONFIG_CREDENTIALS,
             UserManager.DISALLOW_REMOVE_USER,
@@ -117,6 +118,7 @@
      * User restrictions that can not be set by profile owners.
      */
     private static final Set<String> DEVICE_OWNER_ONLY_RESTRICTIONS = Sets.newArraySet(
+            UserManager.DISALLOW_BLUETOOTH,
             UserManager.DISALLOW_USB_FILE_TRANSFER,
             UserManager.DISALLOW_CONFIG_TETHERING,
             UserManager.DISALLOW_NETWORK_RESET,
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index f48db05..a1cce2b 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -265,6 +265,7 @@
     static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP = 2;
     static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME = 3;
     static final int SHORT_PRESS_POWER_GO_HOME = 4;
+    static final int SHORT_PRESS_POWER_CLOSE_IME_OR_GO_HOME = 5;
 
     static final int LONG_PRESS_POWER_NOTHING = 0;
     static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
@@ -1345,6 +1346,14 @@
                 case SHORT_PRESS_POWER_GO_HOME:
                     launchHomeFromHotKey(true /* awakenFromDreams */, false /*respectKeyguard*/);
                     break;
+                case SHORT_PRESS_POWER_CLOSE_IME_OR_GO_HOME:
+                    if (mWindowManagerFuncs.isInputMethodWindowVisible()) {
+                        mWindowManagerFuncs.hideCurrentInputMethod();
+                    } else {
+                        launchHomeFromHotKey(true /* awakenFromDreams */,
+                            false /*respectKeyguard*/);
+                    }
+                    break;
             }
         }
     }
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
index 61319cf..7ba95a4 100644
--- a/services/core/java/com/android/server/webkit/SystemImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -291,5 +291,5 @@
     // flags declaring we want extra info from the package manager for webview providers
     private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
             | PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING
-            | PackageManager.MATCH_UNINSTALLED_PACKAGES;
+            | PackageManager.MATCH_ANY_USER;
 }
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 5d739d1..5838a37 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1103,6 +1103,11 @@
         return mOrientation;
     }
 
+    /** Returns the app's preferred orientation regardless of its currently visibility state. */
+    int getOrientationIgnoreVisibility() {
+        return mOrientation;
+    }
+
     @Override
     void checkAppWindowsReadyToShow() {
         if (allDrawn == mAppAnimator.allDrawn) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e73acde..79d58a3 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -141,8 +141,6 @@
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.function.Consumer;
-import java.util.function.Function;
 
 /**
  * Utility class for keeping track of the WindowStates and other pertinent contents of a
@@ -459,6 +457,43 @@
     }
 
     @Override
+    boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
+        // Special handling so we can process IME windows with #forAllImeWindows above their IME
+        // target, or here in order if there isn't an IME target.
+        if (traverseTopToBottom) {
+            for (int i = mChildren.size() - 1; i >= 0; --i) {
+                final DisplayChildWindowContainer child = mChildren.get(i);
+                if (child == mImeWindowsContainers && mService.mInputMethodTarget != null) {
+                    // In this case the Ime windows will be processed above their target so we skip
+                    // here.
+                    continue;
+                }
+                if (child.forAllWindows(callback, traverseTopToBottom)) {
+                    return true;
+                }
+            }
+        } else {
+            final int count = mChildren.size();
+            for (int i = 0; i < count; i++) {
+                final DisplayChildWindowContainer child = mChildren.get(i);
+                if (child == mImeWindowsContainers && mService.mInputMethodTarget != null) {
+                    // In this case the Ime windows will be processed above their target so we skip
+                    // here.
+                    continue;
+                }
+                if (child.forAllWindows(callback, traverseTopToBottom)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    boolean forAllImeWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
+        return mImeWindowsContainers.forAllWindows(callback, traverseTopToBottom);
+    }
+
+    @Override
     int getOrientation() {
         final WindowManagerPolicy policy = mService.mPolicy;
 
@@ -2546,7 +2581,7 @@
             if (!obscured) {
                 final boolean isDisplayed = w.isDisplayedLw();
 
-                if (isDisplayed && w.isObscuringFullscreen(mDisplayInfo)) {
+                if (isDisplayed && w.isObscuringDisplay()) {
                     // This window completely covers everything behind it, so we want to leave all
                     // of them as undimmed (for performance reasons).
                     root.mObscuringWindow = w;
@@ -2945,7 +2980,7 @@
                     screenshotReady = true;
                 }
 
-                if (ws.isObscuringFullscreen(mDisplayInfo)){
+                if (ws.isObscuringDisplay()){
                     break;
                 }
             }
diff --git a/services/core/java/com/android/server/wm/DragResizeMode.java b/services/core/java/com/android/server/wm/DragResizeMode.java
index 08acf9d..8ab0406 100644
--- a/services/core/java/com/android/server/wm/DragResizeMode.java
+++ b/services/core/java/com/android/server/wm/DragResizeMode.java
@@ -20,6 +20,7 @@
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
 
 /**
  * Describes the mode in which a window is drag resizing.
@@ -45,7 +46,8 @@
             case DRAG_RESIZE_MODE_DOCKED_DIVIDER:
                 return stackId == DOCKED_STACK_ID
                         || stackId == FULLSCREEN_WORKSPACE_STACK_ID
-                        || stackId == HOME_STACK_ID;
+                        || stackId == HOME_STACK_ID
+                        || stackId == RECENTS_STACK_ID;
             default:
                 return false;
         }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index b889db2..d33ae48 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -19,7 +19,7 @@
 import static android.app.ActivityManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -526,10 +526,6 @@
         return (tokensCount != 0) && mChildren.get(tokensCount - 1).showForAllUsers;
     }
 
-    boolean inHomeStack() {
-        return mStack != null && mStack.mStackId == HOME_STACK_ID;
-    }
-
     boolean inFreeformWorkspace() {
         return mStack != null && mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
     }
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 203ba72..a90b615 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -1183,7 +1183,7 @@
 
     @Override
     public boolean dimFullscreen() {
-        return mStackId == HOME_STACK_ID || fillsParent();
+        return StackId.isHomeOrRecentsStack(mStackId) || fillsParent();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
index 32373f9..c2988ad 100644
--- a/services/core/java/com/android/server/wm/WindowLayersController.java
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -66,6 +66,8 @@
     private boolean mAnyLayerChanged;
     private int mHighestLayerInImeTargetBaseLayer;
     private WindowState mImeTarget;
+    private boolean mAboveImeTarget;
+    private ArrayDeque<WindowState> mAboveImeTargetAppWindows = new ArrayDeque();
 
     final void assignWindowLayers(DisplayContent dc) {
         if (DEBUG_LAYERS) Slog.v(TAG_WM, "Assigning layers based",
@@ -143,6 +145,8 @@
 
         mImeTarget = mService.mInputMethodTarget;
         mHighestLayerInImeTargetBaseLayer = (mImeTarget != null) ? mImeTarget.mBaseLayer : 0;
+        mAboveImeTarget = false;
+        mAboveImeTargetAppWindows.clear();
     }
 
     private void collectSpecialWindows(WindowState w) {
@@ -157,6 +161,20 @@
             mInputMethodWindows.add(w);
             return;
         }
+        if (mImeTarget != null) {
+            if (w.getParentWindow() == mImeTarget && w.mSubLayer > 0) {
+                // Child windows of the ime target with a positive sub-layer should be placed above
+                // the IME.
+                mAboveImeTargetAppWindows.add(w);
+            } else if (mAboveImeTarget && w.mAppToken != null) {
+                // windows of apps above the IME target should be placed above the IME.
+                mAboveImeTargetAppWindows.add(w);
+            }
+            if (w == mImeTarget) {
+                mAboveImeTarget = true;
+            }
+        }
+
         final Task task = w.getTask();
         if (task == null) {
             return;
@@ -211,6 +229,12 @@
             while (!mInputMethodWindows.isEmpty()) {
                 layer = assignAndIncreaseLayerIfNeeded(mInputMethodWindows.remove(), layer);
             }
+
+            // Adjust app windows the should be displayed above the IME since they are above the IME
+            // target.
+            while (!mAboveImeTargetAppWindows.isEmpty()) {
+                layer = assignAndIncreaseLayerIfNeeded(mAboveImeTargetAppWindows.remove(), layer);
+            }
         }
 
     }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f51b6a0..51e8a56 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -214,6 +214,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
@@ -1414,7 +1415,8 @@
             winAnimator.mEnterAnimationPending = true;
             winAnimator.mEnteringAnimation = true;
             // Check if we need to prepare a transition for replacing window first.
-            if (atoken != null && !prepareWindowReplacementTransition(atoken)) {
+            if (atoken != null && atoken.isVisible()
+                    && !prepareWindowReplacementTransition(atoken)) {
                 // If not, check if need to set up a dummy transition during display freeze
                 // so that the unfreeze wait for the apps to draw. This might be needed if
                 // the app is relaunching.
@@ -2715,7 +2717,7 @@
                 return SCREEN_ORIENTATION_UNSPECIFIED;
             }
 
-            return wtoken.getOrientation();
+            return wtoken.getOrientationIgnoreVisibility();
         }
     }
 
@@ -4088,6 +4090,24 @@
         }
     }
 
+    // Called by window manager policy.  Not exposed externally.
+    @Override
+    public boolean isInputMethodWindowVisible() {
+        synchronized (mWindowMap) {
+            return mInputMethodWindow != null && mInputMethodWindow.isVisibleLw();
+        }
+    }
+
+    // Called by window manager policy.  Not exposed externally.
+    @Override
+    public void hideCurrentInputMethod() {
+        final InputMethodManagerInternal inputMethodManagerInternal =
+            LocalServices.getService(InputMethodManagerInternal.class);
+        if (inputMethodManagerInternal != null) {
+            inputMethodManagerInternal.hideCurrentInputMethod();
+        }
+    }
+
     // Called by window manager policy. Not exposed externally.
     @Override
     public void lockDeviceNow() {
@@ -6470,7 +6490,15 @@
                 case SEND_NEW_CONFIGURATION: {
                     removeMessages(SEND_NEW_CONFIGURATION, msg.obj);
                     final int displayId = (Integer) msg.obj;
-                    sendNewConfiguration(displayId);
+                    if (mRoot.getDisplayContent(displayId) != null) {
+                        sendNewConfiguration(displayId);
+                    } else {
+                        // Message could come after display has already been removed.
+                        if (DEBUG_CONFIGURATION) {
+                            Slog.w(TAG, "Trying to send configuration to non-existing displayId="
+                                    + displayId);
+                        }
+                    }
                     break;
                 }
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 59c9102..1b5e817 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -60,8 +60,6 @@
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.LinkedList;
-import java.util.function.Consumer;
-import java.util.function.Function;
 import java.util.function.Predicate;
 
 import static android.app.ActivityManager.StackId;
@@ -91,7 +89,6 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
@@ -1654,18 +1651,16 @@
                 && (!mIsChildWindow || !getParentWindow().hasMoved());
     }
 
-    boolean isObscuringFullscreen(final DisplayInfo displayInfo) {
+    boolean isObscuringDisplay() {
         Task task = getTask();
         if (task != null && task.mStack != null && !task.mStack.fillsParent()) {
             return false;
         }
-        if (!isOpaqueDrawn() || !isFrameFullscreen(displayInfo)) {
-            return false;
-        }
-        return true;
+        return isOpaqueDrawn() && fillsDisplay();
     }
 
-    boolean isFrameFullscreen(final DisplayInfo displayInfo) {
+    boolean fillsDisplay() {
+        final DisplayInfo displayInfo = getDisplayInfo();
         return mFrame.left <= 0 && mFrame.top <= 0
                 && mFrame.right >= displayInfo.appWidth && mFrame.bottom >= displayInfo.appHeight;
     }
@@ -3190,7 +3185,8 @@
     }
 
     boolean isDockedResizing() {
-        return mDragResizing && getResizeMode() == DRAG_RESIZE_MODE_DOCKED_DIVIDER;
+        return (mDragResizing && getResizeMode() == DRAG_RESIZE_MODE_DOCKED_DIVIDER)
+                || (isChildWindow() && getParentWindow().isDockedResizing());
     }
 
     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
@@ -3255,7 +3251,7 @@
                     pw.print(mPolicyVisibilityAfterAnim);
                     pw.print(" mAppOpVisibility=");
                     pw.print(mAppOpVisibility);
-                    pw.print(" parentHidden="); pw.println(isParentWindowHidden());
+                    pw.print(" parentHidden="); pw.print(isParentWindowHidden());
                     pw.print(" mPermanentlyHidden="); pw.println(mPermanentlyHidden);
         }
         if (!mRelayoutCalled || mLayoutNeeded) {
@@ -3841,7 +3837,7 @@
     boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
         if (mChildren.isEmpty()) {
             // The window has no children so we just return it.
-            return callback.apply(this);
+            return applyInOrderWithImeWindows(callback, traverseTopToBottom);
         }
 
         if (traverseTopToBottom) {
@@ -3870,7 +3866,7 @@
             child = mChildren.get(i);
         }
 
-        if (callback.apply(this)) {
+        if (applyInOrderWithImeWindows(callback, false /* traverseTopToBottom */)) {
             return true;
         }
 
@@ -3906,7 +3902,7 @@
             child = mChildren.get(i);
         }
 
-        if (callback.apply(this)) {
+        if (applyInOrderWithImeWindows(callback, true /* traverseTopToBottom */)) {
             return true;
         }
 
@@ -3924,6 +3920,35 @@
         return false;
     }
 
+    private boolean applyInOrderWithImeWindows(ToBooleanFunction<WindowState> callback,
+            boolean traverseTopToBottom) {
+        if (traverseTopToBottom) {
+            if (mService.mInputMethodTarget == this) {
+                // This window is the current IME target, so we need to process the IME windows
+                // directly above it.
+                if (getDisplayContent().forAllImeWindows(callback, traverseTopToBottom)) {
+                    return true;
+                }
+            }
+            if (callback.apply(this)) {
+                return true;
+            }
+        } else {
+            if (callback.apply(this)) {
+                return true;
+            }
+            if (mService.mInputMethodTarget == this) {
+                // This window is the current IME target, so we need to process the IME windows
+                // directly above it.
+                if (getDisplayContent().forAllImeWindows(callback, traverseTopToBottom)) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
     WindowState getWindow(Predicate<WindowState> callback) {
         if (callback.test(this)) {
             return this;
@@ -4144,6 +4169,105 @@
         }
     }
 
+    /**
+     * Calculate the window crop according to system decor policy. In general this is
+     * the system decor rect (see #calculateSystemDecorRect), but we also have some
+     * special cases. This rectangle is in screen space.
+     */
+    void calculatePolicyCrop(Rect policyCrop) {
+        final DisplayContent displayContent = getDisplayContent();
+        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+
+        if (!isDefaultDisplay()) {
+            // On a different display there is no system decor. Crop the window
+            // by the screen boundaries.
+            // TODO(multi-display)
+            policyCrop.set(0, 0, mCompatFrame.width(), mCompatFrame.height());
+            policyCrop.intersect(-mCompatFrame.left, -mCompatFrame.top,
+                    displayInfo.logicalWidth - mCompatFrame.left,
+                    displayInfo.logicalHeight - mCompatFrame.top);
+        } else if (mLayer >= mService.mSystemDecorLayer) {
+            // Above the decor layer is easy, just use the entire window
+            policyCrop.set(0, 0, mCompatFrame.width(), mCompatFrame.height());
+        } else if (mDecorFrame.isEmpty()) {
+            // Windows without policy decor aren't cropped.
+            policyCrop.set(0, 0, mCompatFrame.width(), mCompatFrame.height());
+        } else {
+            // Crop to the system decor specified by policy.
+            calculateSystemDecorRect(policyCrop);
+        }
+    }
+
+    /**
+     * The system decor rect is the region of the window which is not covered
+     * by system decorations.
+     */
+    private void calculateSystemDecorRect(Rect systemDecorRect) {
+        final Rect decorRect = mDecorFrame;
+        final int width = mFrame.width();
+        final int height = mFrame.height();
+
+        // Compute the offset of the window in relation to the decor rect.
+        final int left = mXOffset + mFrame.left;
+        final int top = mYOffset + mFrame.top;
+
+        // Initialize the decor rect to the entire frame.
+        if (isDockedResizing()) {
+            // If we are resizing with the divider, the task bounds might be smaller than the
+            // stack bounds. The system decor is used to clip to the task bounds, which we don't
+            // want in this case in order to avoid holes.
+            //
+            // We take care to not shrink the width, for surfaces which are larger than
+            // the display region. Of course this area will not eventually be visible
+            // but if we truncate the width now, we will calculate incorrectly
+            // when adjusting to the stack bounds.
+            final DisplayInfo displayInfo = getDisplayContent().getDisplayInfo();
+            systemDecorRect.set(0, 0,
+                    Math.max(width, displayInfo.logicalWidth),
+                    Math.max(height, displayInfo.logicalHeight));
+        } else {
+            systemDecorRect.set(0, 0, width, height);
+        }
+
+        // If a freeform window is animating from a position where it would be cutoff, it would be
+        // cutoff during the animation. We don't want that, so for the duration of the animation
+        // we ignore the decor cropping and depend on layering to position windows correctly.
+        final boolean cropToDecor = !(inFreeformWorkspace() && isAnimatingLw());
+        if (cropToDecor) {
+            // Intersect with the decor rect, offsetted by window position.
+            systemDecorRect.intersect(decorRect.left - left, decorRect.top - top,
+                    decorRect.right - left, decorRect.bottom - top);
+        }
+
+        // If size compatibility is being applied to the window, the
+        // surface is scaled relative to the screen.  Also apply this
+        // scaling to the crop rect.  We aren't using the standard rect
+        // scale function because we want to round things to make the crop
+        // always round to a larger rect to ensure we don't crop too
+        // much and hide part of the window that should be seen.
+        if (mEnforceSizeCompat && mInvGlobalScale != 1.0f) {
+            final float scale = mInvGlobalScale;
+            systemDecorRect.left = (int) (systemDecorRect.left * scale - 0.5f);
+            systemDecorRect.top = (int) (systemDecorRect.top * scale - 0.5f);
+            systemDecorRect.right = (int) ((systemDecorRect.right + 1) * scale - 0.5f);
+            systemDecorRect.bottom = (int) ((systemDecorRect.bottom + 1) * scale - 0.5f);
+        }
+
+    }
+
+    /**
+     * Expand the given rectangle by this windows surface insets. This
+     * takes you from the 'window size' to the 'surface size'.
+     * The surface insets are positive in each direction, so we inset by
+     * the inverse.
+     */
+    void expandForSurfaceInsets(Rect r) {
+        r.inset(-mAttrs.surfaceInsets.left,
+                -mAttrs.surfaceInsets.top,
+                -mAttrs.surfaceInsets.right,
+                -mAttrs.surfaceInsets.bottom);
+    }
+
     // TODO: Hack to work around the number of states AppWindowToken needs to access without having
     // access to its windows children. Need to investigate re-writing
     // {@link AppWindowToken#updateReportedVisibilityLocked} so this can be removed.
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index a428cce..37bd402 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -22,6 +22,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static com.android.server.wm.AppWindowAnimator.sDummyAnimation;
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
@@ -56,7 +57,6 @@
 import android.util.Slog;
 import android.view.DisplayInfo;
 import android.view.MagnificationSpec;
-import android.view.Surface;
 import android.view.Surface.OutOfResourcesException;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
@@ -1068,101 +1068,75 @@
         }
     }
 
-    private void calculateSystemDecorRect() {
-        final WindowState w = mWin;
-        final Rect decorRect = w.mDecorFrame;
-        final int width = w.mFrame.width();
-        final int height = w.mFrame.height();
-
-        // Compute the offset of the window in relation to the decor rect.
-        final int left = w.mXOffset + w.mFrame.left;
-        final int top = w.mYOffset + w.mFrame.top;
-
-        // Initialize the decor rect to the entire frame.
-        if (w.isDockedResizing() ||
-                (w.isChildWindow() && w.getParentWindow().isDockedResizing())) {
-
-            // If we are resizing with the divider, the task bounds might be smaller than the
-            // stack bounds. The system decor is used to clip to the task bounds, which we don't
-            // want in this case in order to avoid holes.
-            //
-            // We take care to not shrink the width, for surfaces which are larger than
-            // the display region. Of course this area will not eventually be visible
-            // but if we truncate the width now, we will calculate incorrectly
-            // when adjusting to the stack bounds.
-            final DisplayInfo displayInfo = w.getDisplayContent().getDisplayInfo();
-            mSystemDecorRect.set(0, 0,
-                    Math.max(width, displayInfo.logicalWidth),
-                    Math.max(height, displayInfo.logicalHeight));
-        } else {
-            mSystemDecorRect.set(0, 0, width, height);
-        }
-
-        // If a freeform window is animating from a position where it would be cutoff, it would be
-        // cutoff during the animation. We don't want that, so for the duration of the animation
-        // we ignore the decor cropping and depend on layering to position windows correctly.
-        final boolean cropToDecor = !(w.inFreeformWorkspace() && w.isAnimatingLw());
-        if (cropToDecor) {
-            // Intersect with the decor rect, offsetted by window position.
-            mSystemDecorRect.intersect(decorRect.left - left, decorRect.top - top,
-                    decorRect.right - left, decorRect.bottom - top);
-        }
-
-        // If size compatibility is being applied to the window, the
-        // surface is scaled relative to the screen.  Also apply this
-        // scaling to the crop rect.  We aren't using the standard rect
-        // scale function because we want to round things to make the crop
-        // always round to a larger rect to ensure we don't crop too
-        // much and hide part of the window that should be seen.
-        if (w.mEnforceSizeCompat && w.mInvGlobalScale != 1.0f) {
-            final float scale = w.mInvGlobalScale;
-            mSystemDecorRect.left = (int) (mSystemDecorRect.left * scale - 0.5f);
-            mSystemDecorRect.top = (int) (mSystemDecorRect.top * scale - 0.5f);
-            mSystemDecorRect.right = (int) ((mSystemDecorRect.right + 1) * scale - 0.5f);
-            mSystemDecorRect.bottom = (int) ((mSystemDecorRect.bottom + 1) * scale - 0.5f);
-        }
+    /**
+     * In some scenarios we use a screen space clip rect (so called, final clip rect)
+     * to crop to stack bounds. Generally because it's easier to deal with while
+     * animating.
+     *
+     * @return True in scenarios where we use the final clip rect for stack clipping.
+     */
+    private boolean useFinalClipRect() {
+        return (isAnimationSet() && resolveStackClip() == STACK_CLIP_AFTER_ANIM)
+                || mDestroyPreservedSurfaceUponRedraw || mWin.inPinnedWorkspace();
     }
 
-    void calculateSurfaceWindowCrop(Rect clipRect, Rect finalClipRect) {
+    /**
+     * Calculate the screen-space crop rect and fill finalClipRect.
+     * @return true if finalClipRect has been filled, otherwise,
+     * no screen space crop should be applied.
+     */
+    private boolean calculateFinalCrop(Rect finalClipRect) {
         final WindowState w = mWin;
         final DisplayContent displayContent = w.getDisplayContent();
+        finalClipRect.setEmpty();
+
         if (displayContent == null) {
-            clipRect.setEmpty();
-            finalClipRect.setEmpty();
-            return;
+            return false;
         }
-        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+
+        if (!shouldCropToStackBounds() || !useFinalClipRect()) {
+            return false;
+        }
+
+        // Task is non-null per shouldCropToStackBounds
+        final TaskStack stack = w.getTask().mStack;
+        stack.getDimBounds(finalClipRect);
+        w.expandForSurfaceInsets(finalClipRect);
+        return true;
+    }
+
+    /**
+     * Calculate the window-space crop rect and fill clipRect.
+     * @return true if clipRect has been filled otherwise, no window space crop should be applied.
+     */
+    private boolean calculateCrop(Rect clipRect) {
+        final WindowState w = mWin;
+        final DisplayContent displayContent = w.getDisplayContent();
+        clipRect.setEmpty();
+
+        if (displayContent == null) {
+            return false;
+        }
+
+        if (w.inPinnedWorkspace()) {
+            return false;
+        }
+
+        // If we're animating, the wallpaper should only
+        // be updated at the end of the animation.
+        if (w.mAttrs.type == TYPE_WALLPAPER) {
+            return false;
+        }
+
         if (DEBUG_WINDOW_CROP) Slog.d(TAG,
                 "Updating crop win=" + w + " mLastCrop=" + mLastClipRect);
 
-        // Need to recompute a new system decor rect each time.
-        if (!w.isDefaultDisplay()) {
-            // On a different display there is no system decor.  Crop the window
-            // by the screen boundaries.
-            mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height());
-            mSystemDecorRect.intersect(-w.mCompatFrame.left, -w.mCompatFrame.top,
-                    displayInfo.logicalWidth - w.mCompatFrame.left,
-                    displayInfo.logicalHeight - w.mCompatFrame.top);
-        } else if (w.mLayer >= mService.mSystemDecorLayer) {
-            // Above the decor layer is easy, just use the entire window.
-            mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height());
-        } else if (w.mDecorFrame.isEmpty()) {
-            // Windows without policy decor aren't cropped.
-            mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height());
-        } else if (w.mAttrs.type == LayoutParams.TYPE_WALLPAPER && mAnimator.isAnimating()) {
-            // If we're animating, the wallpaper crop should only be updated at the end of the
-            // animation.
-            mTmpClipRect.set(mSystemDecorRect);
-            calculateSystemDecorRect();
-            mSystemDecorRect.union(mTmpClipRect);
-        } else {
-            // Crop to the system decor specified by policy.
-            calculateSystemDecorRect();
-            if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop win=" + w + " mDecorFrame="
-                    + w.mDecorFrame + " mSystemDecorRect=" + mSystemDecorRect);
-        }
+        w.calculatePolicyCrop(mSystemDecorRect);
 
-        final boolean fullscreen = w.isFrameFullscreen(displayInfo);
+        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop win=" + w + " mDecorFrame="
+                + w.mDecorFrame + " mSystemDecorRect=" + mSystemDecorRect);
+
+        final boolean fullscreen = w.fillsDisplay();
         final boolean isFreeformResizing =
                 w.isDragResizing() && w.getResizeMode() == DRAG_RESIZE_MODE_FREEFORM;
 
@@ -1178,12 +1152,7 @@
             clipRect.offset(w.mShownPosition.x, w.mShownPosition.y);
         }
 
-        // Expand the clip rect for surface insets.
-        final WindowManager.LayoutParams attrs = w.mAttrs;
-        clipRect.left -= attrs.surfaceInsets.left;
-        clipRect.top -= attrs.surfaceInsets.top;
-        clipRect.right += attrs.surfaceInsets.right;
-        clipRect.bottom += attrs.surfaceInsets.bottom;
+        w.expandForSurfaceInsets(clipRect);
 
         if (mHasClipRect && fullscreen) {
             // We intersect the clip rect specified by the transformation with the expanded system
@@ -1193,10 +1162,11 @@
         }
         // The clip rect was generated assuming (0,0) as the window origin,
         // so we need to translate to match the actual surface coordinates.
-        clipRect.offset(attrs.surfaceInsets.left, attrs.surfaceInsets.top);
+        clipRect.offset(w.mAttrs.surfaceInsets.left, w.mAttrs.surfaceInsets.top);
 
-        finalClipRect.setEmpty();
-        adjustCropToStackBounds(w, clipRect, finalClipRect, isFreeformResizing);
+        if (!useFinalClipRect()) {
+            adjustCropToStackBounds(clipRect, isFreeformResizing);
+        }
         if (DEBUG_WINDOW_CROP) Slog.d(TAG,
                 "win=" + w + " Clip rect after stack adjustment=" + clipRect);
 
@@ -1206,10 +1176,11 @@
         if (w.hasJustMovedInStack() && mLastClipRect.isEmpty() && !clipRect.isEmpty()) {
             clipRect.setEmpty();
         }
+        return true;
     }
 
-    void updateSurfaceWindowCrop(Rect clipRect, Rect finalClipRect, boolean recoveringMemory) {
-        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "updateSurfaceWindowCrop: win=" + mWin
+    private void applyCrop(Rect clipRect, Rect finalClipRect, boolean recoveringMemory) {
+        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "applyCrop: win=" + mWin
                 + " clipRect=" + clipRect + " finalClipRect=" + finalClipRect);
         if (clipRect != null) {
             if (!clipRect.equals(mLastClipRect)) {
@@ -1219,6 +1190,11 @@
         } else {
             mSurfaceController.clearCropInTransaction(recoveringMemory);
         }
+
+        if (finalClipRect == null) {
+            finalClipRect = mService.mTmpRect;
+            finalClipRect.setEmpty();
+        }
         if (!finalClipRect.equals(mLastFinalClipRect)) {
             mLastFinalClipRect.set(finalClipRect);
             mSurfaceController.setFinalCropInTransaction(finalClipRect);
@@ -1236,9 +1212,9 @@
             return mStackClip;
         }
     }
-    private void adjustCropToStackBounds(WindowState w, Rect clipRect, Rect finalClipRect,
-            boolean isFreeformResizing) {
 
+    private boolean shouldCropToStackBounds() {
+        final WindowState w = mWin;
         final DisplayContent displayContent = w.getDisplayContent();
         if (displayContent != null && !displayContent.isDefaultDisplay) {
             // There are some windows that live on other displays while their app and main window
@@ -1246,22 +1222,32 @@
             // to the stack bounds which is only currently supported on the default display.
             // TODO(multi-display): Need to support cropping to stack bounds on other displays
             // when we have stacks on other displays.
-            return;
+            return false;
         }
 
         final Task task = w.getTask();
         if (task == null || !task.cropWindowsToStackBounds()) {
-            return;
+            return false;
         }
 
         final int stackClip = resolveStackClip();
 
         // It's animating and we don't want to clip it to stack bounds during animation - abort.
         if (isAnimationSet() && stackClip == STACK_CLIP_NONE) {
+            return false;
+        }
+        return true;
+    }
+
+    private void adjustCropToStackBounds(Rect clipRect,
+            boolean isFreeformResizing) {
+        final WindowState w = mWin;
+
+        if (!shouldCropToStackBounds()) {
             return;
         }
 
-        final TaskStack stack = task.mStack;
+        final TaskStack stack = w.getTask().mStack;
         stack.getDimBounds(mTmpStackBounds);
         final Rect surfaceInsets = w.getAttrs().surfaceInsets;
         // When we resize we use the big surface approach, which means we can't trust the
@@ -1272,34 +1258,25 @@
         final int frameY = isFreeformResizing ? (int) mSurfaceController.getY() :
                 w.mFrame.top + mWin.mYOffset - surfaceInsets.top;
 
-        // If we are animating, we either apply the clip before applying all the animation
-        // transformation or after all the transformation.
-        final boolean useFinalClipRect = isAnimationSet() && stackClip == STACK_CLIP_AFTER_ANIM
-                || mDestroyPreservedSurfaceUponRedraw;
-
         // We need to do some acrobatics with surface position, because their clip region is
         // relative to the inside of the surface, but the stack bounds aren't.
-        if (useFinalClipRect) {
-            finalClipRect.set(mTmpStackBounds);
-        } else {
-            if (StackId.hasWindowShadow(stack.mStackId)
-                    && !StackId.isTaskResizeAllowed(stack.mStackId)) {
+        if (StackId.hasWindowShadow(stack.mStackId)
+                && !StackId.isTaskResizeAllowed(stack.mStackId)) {
                 // The windows in this stack display drop shadows and the fill the entire stack
                 // area. Adjust the stack bounds we will use to cropping take into account the
                 // offsets we use to display the drop shadow so it doesn't get cropped.
                 mTmpStackBounds.inset(-surfaceInsets.left, -surfaceInsets.top,
                         -surfaceInsets.right, -surfaceInsets.bottom);
-            }
-
-            clipRect.left = Math.max(0,
-                    Math.max(mTmpStackBounds.left, frameX + clipRect.left) - frameX);
-            clipRect.top = Math.max(0,
-                    Math.max(mTmpStackBounds.top, frameY + clipRect.top) - frameY);
-            clipRect.right = Math.max(0,
-                    Math.min(mTmpStackBounds.right, frameX + clipRect.right) - frameX);
-            clipRect.bottom = Math.max(0,
-                    Math.min(mTmpStackBounds.bottom, frameY + clipRect.bottom) - frameY);
         }
+
+        clipRect.left = Math.max(0,
+                Math.max(mTmpStackBounds.left, frameX + clipRect.left) - frameX);
+        clipRect.top = Math.max(0,
+                Math.max(mTmpStackBounds.top, frameY + clipRect.top) - frameY);
+        clipRect.right = Math.max(0,
+                Math.min(mTmpStackBounds.right, frameX + clipRect.right) - frameX);
+        clipRect.bottom = Math.max(0,
+                Math.min(mTmpStackBounds.bottom, frameY + clipRect.bottom) - frameY);
     }
 
     void setSurfaceBoundariesLocked(final boolean recoveringMemory) {
@@ -1339,7 +1316,13 @@
         // updates until a resize occurs.
         mService.markForSeamlessRotation(w, w.mSeamlesslyRotated && !mSurfaceResized);
 
-        calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect);
+        Rect clipRect = null, finalClipRect = null;
+        if (calculateCrop(mTmpClipRect)) {
+            clipRect = mTmpClipRect;
+        }
+        if (calculateFinalCrop(mTmpFinalClipRect)) {
+            finalClipRect = mTmpFinalClipRect;
+        }
 
         float surfaceWidth = mSurfaceController.getWidth();
         float surfaceHeight = mSurfaceController.getHeight();
@@ -1404,16 +1387,8 @@
             mSurfaceController.forceScaleableInTransaction(false);
         }
 
-        Rect clipRect = mTmpClipRect;
-        if (w.inPinnedWorkspace()) {
-            clipRect = null;
-            task.mStack.getDimBounds(mTmpFinalClipRect);
-            mTmpFinalClipRect.inset(-w.mAttrs.surfaceInsets.left, -w.mAttrs.surfaceInsets.top,
-                    -w.mAttrs.surfaceInsets.right, -w.mAttrs.surfaceInsets.bottom);
-        }
-
         if (!w.mSeamlesslyRotated) {
-            updateSurfaceWindowCrop(clipRect, mTmpFinalClipRect, recoveringMemory);
+            applyCrop(clipRect, finalClipRect, recoveringMemory);
             mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * mExtraHScale,
                     mDtDx * w.mVScale * mExtraVScale,
                     mDsDy * w.mHScale * mExtraHScale,
@@ -1571,8 +1546,7 @@
             mService.openSurfaceTransaction();
             mSurfaceController.setPositionInTransaction(mWin.mFrame.left + left,
                     mWin.mFrame.top + top, false);
-            calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect);
-            updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, false);
+            applyCrop(null, null, false);
         } catch (RuntimeException e) {
             Slog.w(TAG, "Error positioning surface of " + mWin
                     + " pos=(" + left + "," + top + ")", e);
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index ac0e622..50a6095 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -73,6 +73,7 @@
     libhwbinder \
     libutils \
     android.hardware.audio.common@2.0 \
+    android.hardware.gnss@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_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index c7d6b95..e46490b 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -22,15 +22,22 @@
 #include <cutils/properties.h>
 #include <utils/Log.h>
 #include <utils/misc.h>
+#include <utils/AndroidThreads.h>
 
 namespace android {
 
+static int start_sensor_service(void* /*unused*/) {
+    SensorService::instantiate();
+    return 0;
+}
+
 static void android_server_SystemServer_startSensorService(JNIEnv* /* env */, jobject /* clazz */) {
     char propBuf[PROPERTY_VALUE_MAX];
     property_get("system_init.startsensorservice", propBuf, "1");
     if (strcmp(propBuf, "1") == 0) {
-        // Start the sensor service
-        SensorService::instantiate();
+        // Start the sensor service in a new thread
+        createThreadEtc(start_sensor_service, nullptr,
+                        "StartSensorThread", PRIORITY_FOREGROUND);
     }
 }
 
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 25e819c..b0a4297 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -18,10 +18,13 @@
 
 #define LOG_NDEBUG 0
 
+#include <android/hardware/gnss/1.0/IGnss.h>
+
+#include <hwbinder/IPCThreadState.h>
+#include <hwbinder/ProcessState.h>
+
 #include "JNIHelp.h"
 #include "jni.h"
-#include "hardware/hardware.h"
-#include "hardware/gps_internal.h"
 #include "hardware_legacy/power.h"
 #include "utils/Log.h"
 #include "utils/misc.h"
@@ -34,6 +37,7 @@
 #include <linux/in6.h>
 #include <pthread.h>
 #include <string.h>
+#include <cinttypes>
 
 static jobject mCallbacksObj = NULL;
 
@@ -58,978 +62,65 @@
 static jmethodID method_reportMeasurementData;
 static jmethodID method_reportNavigationMessages;
 
-static const GpsInterface* sGpsInterface = NULL;
-static const GpsXtraInterface* sGpsXtraInterface = NULL;
-static const AGpsInterface* sAGpsInterface = NULL;
-static const GpsNiInterface* sGpsNiInterface = NULL;
-static const GpsDebugInterface* sGpsDebugInterface = NULL;
-static const AGpsRilInterface* sAGpsRilInterface = NULL;
-static const GpsGeofencingInterface* sGpsGeofencingInterface = NULL;
-static const GpsMeasurementInterface* sGpsMeasurementInterface = NULL;
-static const GpsNavigationMessageInterface* sGpsNavigationMessageInterface = NULL;
-static const GnssConfigurationInterface* sGnssConfigurationInterface = NULL;
+using android::OK;
+using android::sp;
+using android::status_t;
+using android::String16;
 
-#define GPS_MAX_SATELLITE_COUNT 32
-#define GNSS_MAX_SATELLITE_COUNT 64
+using android::hardware::IPCThreadState;
+using android::hardware::ProcessState;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::hidl_vec;
 
-// Let these through, with ID remapped down to 1, 2... by offset
-#define GLONASS_SVID_OFFSET 64
-#define GLONASS_SVID_COUNT 24
-#define BEIDOU_SVID_OFFSET 200
-#define BEIDOU_SVID_COUNT 35
+using android::hardware::gnss::V1_0::IAGnss;
+using android::hardware::gnss::V1_0::IAGnssCallback;
+using android::hardware::gnss::V1_0::IAGnssCallback;
+using android::hardware::gnss::V1_0::IAGnssRil;
+using android::hardware::gnss::V1_0::IAGnssRilCallback;
+using android::hardware::gnss::V1_0::IGnss;
+using android::hardware::gnss::V1_0::IGnssCallback;
+using android::hardware::gnss::V1_0::IGnssConfiguration;
+using android::hardware::gnss::V1_0::IGnssDebug;
+using android::hardware::gnss::V1_0::IGnssGeofenceCallback;
+using android::hardware::gnss::V1_0::IGnssGeofencing;
+using android::hardware::gnss::V1_0::IGnssMeasurement;
+using android::hardware::gnss::V1_0::IGnssMeasurementCallback;
+using android::hardware::gnss::V1_0::IGnssNavigationMessage;
+using android::hardware::gnss::V1_0::IGnssNavigationMessageCallback;
+using android::hardware::gnss::V1_0::IGnssNi;
+using android::hardware::gnss::V1_0::IGnssNiCallback;
+using android::hardware::gnss::V1_0::IGnssXtra;
+using android::hardware::gnss::V1_0::IGnssXtraCallback;
 
-// Let these through, with ID remapped up (33->120 ... 64->151, etc.)
-#define SBAS_SVID_MIN 33
-#define SBAS_SVID_MAX 64
-#define SBAS_SVID_ADD 87
 
-// Let these through, with no ID remapping
-#define QZSS_SVID_MIN 193
-#define QZSS_SVID_MAX 200
-
-#define SVID_SHIFT_WIDTH 7
-#define CONSTELLATION_TYPE_SHIFT_WIDTH 3
-
-// temporary storage for GPS callbacks
-static GnssSvInfo sGnssSvList[GNSS_MAX_SATELLITE_COUNT];
-static size_t sGnssSvListSize;
-static const char* sNmeaString;
-static int sNmeaStringLength;
+sp<IGnss> gnssHal = nullptr;
+sp<IGnssXtra> gnssXtraIface = nullptr;
+sp<IAGnssRil> agnssRilIface = nullptr;
+sp<IGnssGeofencing> gnssGeofencingIface = nullptr;
+sp<IAGnss> agnssIface = nullptr;
+sp<IGnssDebug> gnssDebugIface = nullptr;
+sp<IGnssConfiguration> gnssConfigurationIface = nullptr;
+sp<IGnssNi> gnssNiIface = nullptr;
+sp<IGnssMeasurement> gnssMeasurementIface = nullptr;
+sp<IGnssNavigationMessage> gnssNavigationMessageIface = nullptr;
 
 #define WAKE_LOCK_NAME  "GPS"
 
 namespace android {
 
-static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
-    if (env->ExceptionCheck()) {
-        ALOGE("An exception was thrown by callback '%s'.", methodName);
-        LOGE_EX(env);
-        env->ExceptionClear();
-    }
-}
-
-static void location_callback(GpsLocation* location)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    env->CallVoidMethod(mCallbacksObj, method_reportLocation, location->flags,
-            (jdouble)location->latitude, (jdouble)location->longitude,
-            (jdouble)location->altitude,
-            (jfloat)location->speed, (jfloat)location->bearing,
-            (jfloat)location->accuracy, (jlong)location->timestamp);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-static void status_callback(GpsStatus* status)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    env->CallVoidMethod(mCallbacksObj, method_reportStatus, status->status);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-static void sv_status_callback(GpsSvStatus* sv_status)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    size_t status_size = sv_status->size;
-    // Some drives doesn't set the size field correctly. Assume GpsSvStatus_v1
-    // if it doesn't provide a valid size.
-    if (status_size == 0) {
-        ALOGW("Invalid size of GpsSvStatus found: %zd.", status_size);
-    }
-    sGnssSvListSize = sv_status->num_svs;
-    // Clamp the list size. Legacy GpsSvStatus has only 32 elements in sv_list.
-    if (sGnssSvListSize > GPS_MAX_SATELLITE_COUNT) {
-        ALOGW("Too many satellites %zd. Clamps to %d.",
-              sGnssSvListSize,
-              GPS_MAX_SATELLITE_COUNT);
-        sGnssSvListSize = GPS_MAX_SATELLITE_COUNT;
-    }
-    uint32_t ephemeris_mask = sv_status->ephemeris_mask;
-    uint32_t almanac_mask = sv_status->almanac_mask;
-    uint32_t used_in_fix_mask = sv_status->used_in_fix_mask;
-    for (size_t i = 0; i < sGnssSvListSize; i++) {
-        GnssSvInfo& info = sGnssSvList[i];
-        info.svid = sv_status->sv_list[i].prn;
-        // Defacto mapping from the overused API that was designed for GPS-only
-        if (info.svid >=1 && info.svid <= 32) {
-            info.constellation = GNSS_CONSTELLATION_GPS;
-        } else if (info.svid > GLONASS_SVID_OFFSET &&
-                   info.svid <= GLONASS_SVID_OFFSET + GLONASS_SVID_COUNT) {
-            info.constellation = GNSS_CONSTELLATION_GLONASS;
-            info.svid -= GLONASS_SVID_OFFSET;
-        } else if (info.svid > BEIDOU_SVID_OFFSET &&
-                   info.svid <= BEIDOU_SVID_OFFSET + BEIDOU_SVID_COUNT) {
-            info.constellation = GNSS_CONSTELLATION_BEIDOU;
-            info.svid -= BEIDOU_SVID_OFFSET;
-        } else if (info.svid >= SBAS_SVID_MIN && info.svid <= SBAS_SVID_MAX) {
-            info.constellation = GNSS_CONSTELLATION_SBAS;
-            info.svid += SBAS_SVID_ADD;
-        } else if (info.svid >= QZSS_SVID_MIN && info.svid <= QZSS_SVID_MAX) {
-            info.constellation = GNSS_CONSTELLATION_QZSS;
-        } else {
-            ALOGD("Unknown constellation type with Svid = %d.", info.svid);
-            info.constellation = GNSS_CONSTELLATION_UNKNOWN;
-        }
-        info.c_n0_dbhz = sv_status->sv_list[i].snr;
-        info.elevation = sv_status->sv_list[i].elevation;
-        info.azimuth = sv_status->sv_list[i].azimuth;
-        info.flags = GNSS_SV_FLAGS_NONE;
-        // Only GPS info is valid for these fields, as these masks are just 32 bits, by GPS prn
-        if (info.constellation == GNSS_CONSTELLATION_GPS) {
-            int32_t this_svid_mask = (1 << (info.svid - 1));
-            if ((ephemeris_mask & this_svid_mask) != 0) {
-                info.flags |= GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA;
-            }
-            if ((almanac_mask & this_svid_mask) != 0) {
-                info.flags |= GNSS_SV_FLAGS_HAS_ALMANAC_DATA;
-            }
-            if ((used_in_fix_mask & this_svid_mask) != 0) {
-                info.flags |= GNSS_SV_FLAGS_USED_IN_FIX;
-            }
-        }
-    }
-    env->CallVoidMethod(mCallbacksObj, method_reportSvStatus);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-static void gnss_sv_status_callback(GnssSvStatus* sv_status) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    size_t status_size = sv_status->size;
-    // Check the size, and reject the object that has invalid size.
-    if (status_size != sizeof(GnssSvStatus)) {
-        ALOGE("Invalid size of GnssSvStatus found: %zd.", status_size);
-        return;
-    }
-    sGnssSvListSize = sv_status->num_svs;
-    // Clamp the list size
-    if (sGnssSvListSize > GNSS_MAX_SATELLITE_COUNT) {
-        ALOGD("Too many satellites %zd. Clamps to %d.",
-              sGnssSvListSize,
-              GNSS_MAX_SATELLITE_COUNT);
-        sGnssSvListSize = GNSS_MAX_SATELLITE_COUNT;
-    }
-    // Copy GNSS SV info into sGnssSvList, if any.
-    if (sGnssSvListSize > 0) {
-        memcpy(sGnssSvList,
-               sv_status->gnss_sv_list,
-               sizeof(GnssSvInfo) * sGnssSvListSize);
-    }
-    env->CallVoidMethod(mCallbacksObj, method_reportSvStatus);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-static void nmea_callback(GpsUtcTime timestamp, const char* nmea, int length)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    // The Java code will call back to read these values
-    // We do this to avoid creating unnecessary String objects
-    sNmeaString = nmea;
-    sNmeaStringLength = length;
-    env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-static void set_system_info_callback(const GnssSystemInfo* info) {
-    ALOGD("set_system_info_callback: year_of_hw=%d\n", info->year_of_hw);
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    env->CallVoidMethod(mCallbacksObj, method_setGnssYearOfHardware,
-                        info->year_of_hw);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-static void set_capabilities_callback(uint32_t capabilities)
-{
-    ALOGD("set_capabilities_callback: %du\n", capabilities);
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-static void acquire_wakelock_callback()
-{
-    acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
-}
-
-static void release_wakelock_callback()
-{
-    release_wake_lock(WAKE_LOCK_NAME);
-}
-
-static void request_utc_time_callback()
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg)
-{
-    return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);
-}
-
-GpsCallbacks sGpsCallbacks = {
-    sizeof(GpsCallbacks),
-    location_callback,
-    status_callback,
-    sv_status_callback,
-    nmea_callback,
-    set_capabilities_callback,
-    acquire_wakelock_callback,
-    release_wakelock_callback,
-    create_thread_callback,
-    request_utc_time_callback,
-    set_system_info_callback,
-    gnss_sv_status_callback,
-};
-
-static void xtra_download_request_callback()
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    env->CallVoidMethod(mCallbacksObj, method_xtraDownloadRequest);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-GpsXtraCallbacks sGpsXtraCallbacks = {
-    xtra_download_request_callback,
-    create_thread_callback,
-};
-
-static jbyteArray convert_to_ipv4(uint32_t ip, bool net_order)
-{
-    if (INADDR_NONE == ip) {
-        return NULL;
-    }
-
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    jbyteArray byteArray = env->NewByteArray(4);
-    if (byteArray == NULL) {
-        ALOGE("Unable to allocate byte array for IPv4 address");
-        return NULL;
-    }
-
-    jbyte ipv4[4];
-    if (net_order) {
-        ALOGV("Converting IPv4 address(net_order) %x", ip);
-        memcpy(ipv4, &ip, sizeof(ipv4));
-    } else {
-        ALOGV("Converting IPv4 address(host_order) %x", ip);
-        //endianess transparent conversion from int to char[]
-        ipv4[0] = (jbyte) (ip & 0xFF);
-        ipv4[1] = (jbyte)((ip>>8) & 0xFF);
-        ipv4[2] = (jbyte)((ip>>16) & 0xFF);
-        ipv4[3] = (jbyte) (ip>>24);
-    }
-
-    env->SetByteArrayRegion(byteArray, 0, 4, (const jbyte*) ipv4);
-    return byteArray;
-}
-
-static void agps_status_callback(AGpsStatus* agps_status)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    jbyteArray byteArray = NULL;
-    bool isSupported = false;
-
-    size_t status_size = agps_status->size;
-    if (status_size == sizeof(AGpsStatus)) {
-      ALOGV("AGpsStatus is V3: %zd", status_size);
-      switch (agps_status->addr.ss_family)
-      {
-      case AF_INET:
-          {
-            struct sockaddr_in *in = (struct sockaddr_in*)&(agps_status->addr);
-            uint32_t ipAddr = *(uint32_t*)&(in->sin_addr);
-            byteArray = convert_to_ipv4(ipAddr, true /* net_order */);
-            if (ipAddr == INADDR_NONE || byteArray != NULL) {
-                isSupported = true;
-            }
-            IF_ALOGD() {
-                // log the IP for reference in case there is a bogus value pushed by HAL
-                char str[INET_ADDRSTRLEN];
-                inet_ntop(AF_INET, &(in->sin_addr), str, INET_ADDRSTRLEN);
-                ALOGD("AGPS IP is v4: %s", str);
-            }
-          }
-          break;
-      case AF_INET6:
-          {
-            struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&(agps_status->addr);
-            byteArray = env->NewByteArray(16);
-            if (byteArray != NULL) {
-                env->SetByteArrayRegion(byteArray, 0, 16, (const jbyte *)&(in6->sin6_addr));
-                isSupported = true;
-            } else {
-                ALOGE("Unable to allocate byte array for IPv6 address.");
-            }
-            IF_ALOGD() {
-                // log the IP for reference in case there is a bogus value pushed by HAL
-                char str[INET6_ADDRSTRLEN];
-                inet_ntop(AF_INET6, &(in6->sin6_addr), str, INET6_ADDRSTRLEN);
-                ALOGD("AGPS IP is v6: %s", str);
-            }
-          }
-          break;
-      default:
-          ALOGE("Invalid ss_family found: %d", agps_status->addr.ss_family);
-          break;
-      }
-    } else if (status_size >= sizeof(AGpsStatus_v2)) {
-      ALOGV("AGpsStatus is V2+: %zd", status_size);
-      // for back-compatibility reasons we check in v2 that the data structure size is greater or
-      // equal to the declared size in gps.h
-      uint32_t ipaddr = agps_status->ipaddr;
-      ALOGV("AGPS IP is v4: %x", ipaddr);
-      byteArray = convert_to_ipv4(ipaddr, false /* net_order */);
-      if (ipaddr == INADDR_NONE || byteArray != NULL) {
-          isSupported = true;
-      }
-    } else if (status_size >= sizeof(AGpsStatus_v1)) {
-        ALOGV("AGpsStatus is V1+: %zd", status_size);
-        // because we have to check for >= with regards to v2, we also need to relax the check here
-        // and only make sure that the size is at least what we expect
-        isSupported = true;
-    } else {
-        ALOGE("Invalid size of AGpsStatus found: %zd.", status_size);
-    }
-
-    if (isSupported) {
-        jsize byteArrayLength = byteArray != NULL ? env->GetArrayLength(byteArray) : 0;
-        ALOGV("Passing AGPS IP addr: size %d", byteArrayLength);
-        env->CallVoidMethod(mCallbacksObj, method_reportAGpsStatus, agps_status->type,
-                            agps_status->status, byteArray);
-
-        checkAndClearExceptionFromCallback(env, __FUNCTION__);
-    } else {
-        ALOGD("Skipping calling method_reportAGpsStatus.");
-    }
-
-    if (byteArray) {
-        env->DeleteLocalRef(byteArray);
-    }
-}
-
-AGpsCallbacks sAGpsCallbacks = {
-    agps_status_callback,
-    create_thread_callback,
-};
-
-static void gps_ni_notify_callback(GpsNiNotification *notification)
-{
-    ALOGD("gps_ni_notify_callback\n");
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    jstring requestor_id = env->NewStringUTF(notification->requestor_id);
-    jstring text = env->NewStringUTF(notification->text);
-    jstring extras = env->NewStringUTF(notification->extras);
-
-    if (requestor_id && text && extras) {
-        env->CallVoidMethod(mCallbacksObj, method_reportNiNotification,
-            notification->notification_id, notification->ni_type,
-            notification->notify_flags, notification->timeout,
-            notification->default_response, requestor_id, text,
-            notification->requestor_id_encoding,
-            notification->text_encoding, extras);
-    } else {
-        ALOGE("out of memory in gps_ni_notify_callback\n");
-    }
-
-    if (requestor_id)
-        env->DeleteLocalRef(requestor_id);
-    if (text)
-        env->DeleteLocalRef(text);
-    if (extras)
-        env->DeleteLocalRef(extras);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-GpsNiCallbacks sGpsNiCallbacks = {
-    gps_ni_notify_callback,
-    create_thread_callback,
-};
-
-static void agps_request_set_id(uint32_t flags)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    env->CallVoidMethod(mCallbacksObj, method_requestSetID, flags);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-static void agps_request_ref_location(uint32_t flags)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    env->CallVoidMethod(mCallbacksObj, method_requestRefLocation, flags);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-AGpsRilCallbacks sAGpsRilCallbacks = {
-    agps_request_set_id,
-    agps_request_ref_location,
-    create_thread_callback,
-};
-
-static void gps_geofence_transition_callback(int32_t geofence_id,  GpsLocation* location,
-        int32_t transition, GpsUtcTime timestamp)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-
-    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceTransition, geofence_id,
-            location->flags, (jdouble)location->latitude, (jdouble)location->longitude,
-            (jdouble)location->altitude,
-            (jfloat)location->speed, (jfloat)location->bearing,
-            (jfloat)location->accuracy, (jlong)location->timestamp,
-            transition, timestamp);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-};
-
-static void gps_geofence_status_callback(int32_t status, GpsLocation* location)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    jint flags = 0;
-    jdouble latitude = 0;
-    jdouble longitude = 0;
-    jdouble altitude = 0;
-    jfloat speed = 0;
-    jfloat bearing = 0;
-    jfloat accuracy = 0;
-    jlong timestamp = 0;
-    if (location != NULL) {
-        flags = location->flags;
-        latitude = location->latitude;
-        longitude = location->longitude;
-        altitude = location->altitude;
-        speed = location->speed;
-        bearing = location->bearing;
-        accuracy = location->accuracy;
-        timestamp = location->timestamp;
-    }
-
-    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceStatus, status,
-            flags, latitude, longitude, altitude, speed, bearing, accuracy, timestamp);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-};
-
-static void gps_geofence_add_callback(int32_t geofence_id, int32_t status)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
-        ALOGE("Error in geofence_add_callback: %d\n", status);
-    }
-    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceAddStatus, geofence_id, status);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-};
-
-static void gps_geofence_remove_callback(int32_t geofence_id, int32_t status)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
-        ALOGE("Error in geofence_remove_callback: %d\n", status);
-    }
-    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceRemoveStatus, geofence_id, status);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-};
-
-static void gps_geofence_resume_callback(int32_t geofence_id, int32_t status)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
-        ALOGE("Error in geofence_resume_callback: %d\n", status);
-    }
-    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceResumeStatus, geofence_id, status);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-};
-
-static void gps_geofence_pause_callback(int32_t geofence_id, int32_t status)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
-        ALOGE("Error in geofence_pause_callback: %d\n", status);
-    }
-    env->CallVoidMethod(mCallbacksObj, method_reportGeofencePauseStatus, geofence_id, status);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-};
-
-GpsGeofenceCallbacks sGpsGeofenceCallbacks = {
-    gps_geofence_transition_callback,
-    gps_geofence_status_callback,
-    gps_geofence_add_callback,
-    gps_geofence_remove_callback,
-    gps_geofence_pause_callback,
-    gps_geofence_resume_callback,
-    create_thread_callback,
-};
-
-static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
-    int err;
-    hw_module_t* module;
-
-    method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
-    method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
-    method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
-    method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II[B)V");
-    method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
-    method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
-    method_setGnssYearOfHardware = env->GetMethodID(clazz, "setGnssYearOfHardware", "(I)V");
-    method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
-    method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification",
-            "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
-    method_requestRefLocation = env->GetMethodID(clazz,"requestRefLocation","(I)V");
-    method_requestSetID = env->GetMethodID(clazz,"requestSetID","(I)V");
-    method_requestUtcTime = env->GetMethodID(clazz,"requestUtcTime","()V");
-    method_reportGeofenceTransition = env->GetMethodID(clazz,"reportGeofenceTransition",
-            "(IIDDDFFFJIJ)V");
-    method_reportGeofenceStatus = env->GetMethodID(clazz,"reportGeofenceStatus",
-            "(IIDDDFFFJ)V");
-    method_reportGeofenceAddStatus = env->GetMethodID(clazz,"reportGeofenceAddStatus",
-            "(II)V");
-    method_reportGeofenceRemoveStatus = env->GetMethodID(clazz,"reportGeofenceRemoveStatus",
-            "(II)V");
-    method_reportGeofenceResumeStatus = env->GetMethodID(clazz,"reportGeofenceResumeStatus",
-            "(II)V");
-    method_reportGeofencePauseStatus = env->GetMethodID(clazz,"reportGeofencePauseStatus",
-            "(II)V");
-    method_reportMeasurementData = env->GetMethodID(
-            clazz,
-            "reportMeasurementData",
-            "(Landroid/location/GnssMeasurementsEvent;)V");
-    method_reportNavigationMessages = env->GetMethodID(
-            clazz,
-            "reportNavigationMessage",
-            "(Landroid/location/GnssNavigationMessage;)V");
-
-    err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
-    if (err == 0) {
-        hw_device_t* device;
-        err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
-        if (err == 0) {
-            gps_device_t* gps_device = (gps_device_t *)device;
-            sGpsInterface = gps_device->get_gps_interface(gps_device);
-        }
-    }
-    if (sGpsInterface) {
-        sGpsXtraInterface =
-            (const GpsXtraInterface*)sGpsInterface->get_extension(GPS_XTRA_INTERFACE);
-        sAGpsInterface =
-            (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
-        sGpsNiInterface =
-            (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
-        sGpsDebugInterface =
-            (const GpsDebugInterface*)sGpsInterface->get_extension(GPS_DEBUG_INTERFACE);
-        sAGpsRilInterface =
-            (const AGpsRilInterface*)sGpsInterface->get_extension(AGPS_RIL_INTERFACE);
-        sGpsGeofencingInterface =
-            (const GpsGeofencingInterface*)sGpsInterface->get_extension(GPS_GEOFENCING_INTERFACE);
-        sGpsMeasurementInterface =
-            (const GpsMeasurementInterface*)sGpsInterface->get_extension(GPS_MEASUREMENT_INTERFACE);
-        sGpsNavigationMessageInterface =
-            (const GpsNavigationMessageInterface*)sGpsInterface->get_extension(
-                    GPS_NAVIGATION_MESSAGE_INTERFACE);
-        sGnssConfigurationInterface =
-            (const GnssConfigurationInterface*)sGpsInterface->get_extension(
-                    GNSS_CONFIGURATION_INTERFACE);
-    }
-}
-
-static jboolean android_location_GnssLocationProvider_is_supported(
-        JNIEnv* /* env */, jclass /* clazz */)
-{
-    return (sGpsInterface != NULL) ?  JNI_TRUE : JNI_FALSE;
-}
-
-static jboolean android_location_GnssLocationProvider_is_agps_ril_supported(
-        JNIEnv* /* env */, jclass /* clazz */)
-{
-    return (sAGpsRilInterface != NULL) ? JNI_TRUE : JNI_FALSE;
-}
-
-static jboolean android_location_gpsLocationProvider_is_gnss_configuration_supported(
-        JNIEnv* /* env */, jclass /* jclazz */)
-{
-    return (sGnssConfigurationInterface != NULL) ? JNI_TRUE : JNI_FALSE;
-}
-
-static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject obj)
-{
-    // this must be set before calling into the HAL library
-    if (!mCallbacksObj)
-        mCallbacksObj = env->NewGlobalRef(obj);
-
-    // fail if the main interface fails to initialize
-    if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
-        return JNI_FALSE;
-
-    // if XTRA initialization fails we will disable it by sGpsXtraInterface to NULL,
-    // but continue to allow the rest of the GPS interface to work.
-    if (sGpsXtraInterface && sGpsXtraInterface->init(&sGpsXtraCallbacks) != 0)
-        sGpsXtraInterface = NULL;
-    if (sAGpsInterface)
-        sAGpsInterface->init(&sAGpsCallbacks);
-    if (sGpsNiInterface)
-        sGpsNiInterface->init(&sGpsNiCallbacks);
-    if (sAGpsRilInterface)
-        sAGpsRilInterface->init(&sAGpsRilCallbacks);
-    if (sGpsGeofencingInterface)
-        sGpsGeofencingInterface->init(&sGpsGeofenceCallbacks);
-
-    return JNI_TRUE;
-}
-
-static void android_location_GnssLocationProvider_cleanup(JNIEnv* /* env */, jobject /* obj */)
-{
-    if (sGpsInterface)
-        sGpsInterface->cleanup();
-}
-
-static jboolean android_location_GnssLocationProvider_set_position_mode(JNIEnv* /* env */,
-        jobject /* obj */, jint mode, jint recurrence, jint min_interval, jint preferred_accuracy,
-        jint preferred_time)
-{
-    if (sGpsInterface) {
-        if (sGpsInterface->set_position_mode(mode, recurrence, min_interval, preferred_accuracy,
-                preferred_time) == 0) {
-            return JNI_TRUE;
-        } else {
-            return JNI_FALSE;
-        }
-    }
-    else
-        return JNI_FALSE;
-}
-
-static jboolean android_location_GnssLocationProvider_start(JNIEnv* /* env */, jobject /* obj */)
-{
-    if (sGpsInterface) {
-        if (sGpsInterface->start() == 0) {
-            return JNI_TRUE;
-        } else {
-            return JNI_FALSE;
-        }
-    }
-    else
-        return JNI_FALSE;
-}
-
-static jboolean android_location_GnssLocationProvider_stop(JNIEnv* /* env */, jobject /* obj */)
-{
-    if (sGpsInterface) {
-        if (sGpsInterface->stop() == 0) {
-            return JNI_TRUE;
-        } else {
-            return JNI_FALSE;
-        }
-    }
-    else
-        return JNI_FALSE;
-}
-
-static void android_location_GnssLocationProvider_delete_aiding_data(JNIEnv* /* env */,
-                                                                    jobject /* obj */,
-                                                                    jint flags)
-{
-    if (sGpsInterface)
-        sGpsInterface->delete_aiding_data(flags);
-}
-
-static jint android_location_GnssLocationProvider_read_sv_status(JNIEnv* env, jobject /* obj */,
-        jintArray svidWithFlagArray, jfloatArray cn0Array, jfloatArray elevArray,
-        jfloatArray azumArray)
-{
-    // this should only be called from within a call to reportSvStatus
-    jint* svidWithFlags = env->GetIntArrayElements(svidWithFlagArray, 0);
-    jfloat* cn0s = env->GetFloatArrayElements(cn0Array, 0);
-    jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
-    jfloat* azim = env->GetFloatArrayElements(azumArray, 0);
-
-    // GNSS SV info.
-    for (size_t i = 0; i < sGnssSvListSize; ++i) {
-        const GnssSvInfo& info = sGnssSvList[i];
-        svidWithFlags[i] = (info.svid << SVID_SHIFT_WIDTH) |
-            (info.constellation << CONSTELLATION_TYPE_SHIFT_WIDTH) |
-            info.flags;
-        cn0s[i] = info.c_n0_dbhz;
-        elev[i] = info.elevation;
-        azim[i] = info.azimuth;
-    }
-
-    env->ReleaseIntArrayElements(svidWithFlagArray, svidWithFlags, 0);
-    env->ReleaseFloatArrayElements(cn0Array, cn0s, 0);
-    env->ReleaseFloatArrayElements(elevArray, elev, 0);
-    env->ReleaseFloatArrayElements(azumArray, azim, 0);
-    return (jint) sGnssSvListSize;
-}
-
-static void android_location_GnssLocationProvider_agps_set_reference_location_cellid(
-        JNIEnv* /* env */, jobject /* obj */, jint type, jint mcc, jint mnc, jint lac, jint cid)
-{
-    AGpsRefLocation location;
-
-    if (!sAGpsRilInterface) {
-        ALOGE("no AGPS RIL interface in agps_set_reference_location_cellid");
-        return;
-    }
-
-    switch(type) {
-        case AGPS_REF_LOCATION_TYPE_GSM_CELLID:
-        case AGPS_REF_LOCATION_TYPE_UMTS_CELLID:
-            location.type = type;
-            location.u.cellID.mcc = mcc;
-            location.u.cellID.mnc = mnc;
-            location.u.cellID.lac = lac;
-            location.u.cellID.cid = cid;
-            break;
-        default:
-            ALOGE("Neither a GSM nor a UMTS cellid (%s:%d).",__FUNCTION__,__LINE__);
-            return;
-            break;
-    }
-    sAGpsRilInterface->set_ref_location(&location, sizeof(location));
-}
-
-static void android_location_GnssLocationProvider_agps_send_ni_message(JNIEnv* env,
-        jobject /* obj */, jbyteArray ni_msg, jint size)
-{
-    size_t sz;
-
-    if (!sAGpsRilInterface) {
-        ALOGE("no AGPS RIL interface in send_ni_message");
-        return;
-    }
-    if (size < 0)
-        return;
-    sz = (size_t)size;
-    jbyte* b = env->GetByteArrayElements(ni_msg, 0);
-    sAGpsRilInterface->ni_message((uint8_t *)b,sz);
-    env->ReleaseByteArrayElements(ni_msg,b,0);
-}
-
-static void android_location_GnssLocationProvider_agps_set_id(JNIEnv *env, jobject /* obj */,
-                                                             jint type, jstring  setid_string)
-{
-    if (!sAGpsRilInterface) {
-        ALOGE("no AGPS RIL interface in agps_set_id");
-        return;
-    }
-
-    const char *setid = env->GetStringUTFChars(setid_string, NULL);
-    sAGpsRilInterface->set_set_id(type, setid);
-    env->ReleaseStringUTFChars(setid_string, setid);
-}
-
-static jint android_location_GnssLocationProvider_read_nmea(JNIEnv* env, jobject /* obj */,
-                                            jbyteArray nmeaArray, jint buffer_size)
-{
-    // this should only be called from within a call to reportNmea
-    jbyte* nmea = (jbyte *)env->GetPrimitiveArrayCritical(nmeaArray, 0);
-    int length = sNmeaStringLength;
-    if (length > buffer_size)
-        length = buffer_size;
-    memcpy(nmea, sNmeaString, length);
-    env->ReleasePrimitiveArrayCritical(nmeaArray, nmea, JNI_ABORT);
-    return (jint) length;
-}
-
-static void android_location_GnssLocationProvider_inject_time(JNIEnv* /* env */, jobject /* obj */,
-        jlong time, jlong timeReference, jint uncertainty)
-{
-    if (sGpsInterface)
-        sGpsInterface->inject_time(time, timeReference, uncertainty);
-}
-
-static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env */,
-        jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy)
-{
-    if (sGpsInterface)
-        sGpsInterface->inject_location(latitude, longitude, accuracy);
-}
-
-static jboolean android_location_GnssLocationProvider_supports_xtra(
-        JNIEnv* /* env */, jobject /* obj */)
-{
-    return (sGpsXtraInterface != NULL) ? JNI_TRUE : JNI_FALSE;
-}
-
-static void android_location_GnssLocationProvider_inject_xtra_data(JNIEnv* env, jobject /* obj */,
-        jbyteArray data, jint length)
-{
-    if (!sGpsXtraInterface) {
-        ALOGE("no XTRA interface in inject_xtra_data");
-        return;
-    }
-
-    jbyte* bytes = (jbyte *)env->GetPrimitiveArrayCritical(data, 0);
-    sGpsXtraInterface->inject_xtra_data((char *)bytes, length);
-    env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
-}
-
-static void android_location_GnssLocationProvider_agps_data_conn_open(
-        JNIEnv* env, jobject /* obj */, jstring apn, jint apnIpType)
-{
-    if (!sAGpsInterface) {
-        ALOGE("no AGPS interface in agps_data_conn_open");
-        return;
-    }
-    if (apn == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-        return;
-    }
-
-    const char *apnStr = env->GetStringUTFChars(apn, NULL);
-
-    size_t interface_size = sAGpsInterface->size;
-    if (interface_size == sizeof(AGpsInterface)) {
-        sAGpsInterface->data_conn_open_with_apn_ip_type(apnStr, apnIpType);
-    } else if (interface_size == sizeof(AGpsInterface_v1)) {
-        sAGpsInterface->data_conn_open(apnStr);
-    } else {
-        ALOGE("Invalid size of AGpsInterface found: %zd.", interface_size);
-    }
-
-    env->ReleaseStringUTFChars(apn, apnStr);
-}
-
-static void android_location_GnssLocationProvider_agps_data_conn_closed(JNIEnv* /* env */,
-                                                                       jobject /* obj */)
-{
-    if (!sAGpsInterface) {
-        ALOGE("no AGPS interface in agps_data_conn_closed");
-        return;
-    }
-    sAGpsInterface->data_conn_closed();
-}
-
-static void android_location_GnssLocationProvider_agps_data_conn_failed(JNIEnv* /* env */,
-                                                                       jobject /* obj */)
-{
-    if (!sAGpsInterface) {
-        ALOGE("no AGPS interface in agps_data_conn_failed");
-        return;
-    }
-    sAGpsInterface->data_conn_failed();
-}
-
-static void android_location_GnssLocationProvider_set_agps_server(JNIEnv* env, jobject /* obj */,
-        jint type, jstring hostname, jint port)
-{
-    if (!sAGpsInterface) {
-        ALOGE("no AGPS interface in set_agps_server");
-        return;
-    }
-    const char *c_hostname = env->GetStringUTFChars(hostname, NULL);
-    sAGpsInterface->set_server(type, c_hostname, port);
-    env->ReleaseStringUTFChars(hostname, c_hostname);
-}
-
-static void android_location_GnssLocationProvider_send_ni_response(JNIEnv* /* env */,
-      jobject /* obj */, jint notifId, jint response)
-{
-    if (!sGpsNiInterface) {
-        ALOGE("no NI interface in send_ni_response");
-        return;
-    }
-
-    sGpsNiInterface->respond(notifId, response);
-}
-
-static jstring android_location_GnssLocationProvider_get_internal_state(JNIEnv* env,
-                                                                       jobject /* obj */) {
-    jstring result = NULL;
-    if (sGpsDebugInterface) {
-        const size_t maxLength = 2047;
-        char buffer[maxLength+1];
-        size_t length = sGpsDebugInterface->get_internal_state(buffer, maxLength);
-        if (length > maxLength) length = maxLength;
-        buffer[length] = 0;
-        result = env->NewStringUTF(buffer);
-    }
-    return result;
-}
-
-static void android_location_GnssLocationProvider_update_network_state(JNIEnv* env, jobject /* obj */,
-        jboolean connected, jint type, jboolean roaming, jboolean available, jstring extraInfo, jstring apn)
-{
-
-    if (sAGpsRilInterface && sAGpsRilInterface->update_network_state) {
-        if (extraInfo) {
-            const char *extraInfoStr = env->GetStringUTFChars(extraInfo, NULL);
-            sAGpsRilInterface->update_network_state(connected, type, roaming, extraInfoStr);
-            env->ReleaseStringUTFChars(extraInfo, extraInfoStr);
-        } else {
-            sAGpsRilInterface->update_network_state(connected, type, roaming, NULL);
-        }
-
-        // update_network_availability callback was not included in original AGpsRilInterface
-        if (sAGpsRilInterface->size >= sizeof(AGpsRilInterface)
-                && sAGpsRilInterface->update_network_availability) {
-            const char *c_apn = env->GetStringUTFChars(apn, NULL);
-            sAGpsRilInterface->update_network_availability(available, c_apn);
-            env->ReleaseStringUTFChars(apn, c_apn);
-        }
-    }
-}
-
-static jboolean android_location_GnssLocationProvider_is_geofence_supported(
-        JNIEnv* /* env */, jobject /* obj */)
-{
-    return (sGpsGeofencingInterface != NULL) ? JNI_TRUE : JNI_FALSE;
-}
-
-static jboolean android_location_GnssLocationProvider_add_geofence(JNIEnv* /* env */,
-        jobject /* obj */, jint geofence_id, jdouble latitude, jdouble longitude, jdouble radius,
-        jint last_transition, jint monitor_transition, jint notification_responsiveness,
-        jint unknown_timer) {
-    if (sGpsGeofencingInterface != NULL) {
-        sGpsGeofencingInterface->add_geofence_area(geofence_id, latitude, longitude,
-                radius, last_transition, monitor_transition, notification_responsiveness,
-                unknown_timer);
-        return JNI_TRUE;
-    } else {
-        ALOGE("Geofence interface not available");
-    }
-    return JNI_FALSE;
-}
-
-static jboolean android_location_GnssLocationProvider_remove_geofence(JNIEnv* /* env */,
-        jobject /* obj */, jint geofence_id) {
-    if (sGpsGeofencingInterface != NULL) {
-        sGpsGeofencingInterface->remove_geofence_area(geofence_id);
-        return JNI_TRUE;
-    } else {
-        ALOGE("Geofence interface not available");
-    }
-    return JNI_FALSE;
-}
-
-static jboolean android_location_GnssLocationProvider_pause_geofence(JNIEnv* /* env */,
-        jobject /* obj */, jint geofence_id) {
-    if (sGpsGeofencingInterface != NULL) {
-        sGpsGeofencingInterface->pause_geofence(geofence_id);
-        return JNI_TRUE;
-    } else {
-        ALOGE("Geofence interface not available");
-    }
-    return JNI_FALSE;
-}
-
-static jboolean android_location_GnssLocationProvider_resume_geofence(JNIEnv* /* env */,
-        jobject /* obj */, jint geofence_id, jint monitor_transition) {
-    if (sGpsGeofencingInterface != NULL) {
-        sGpsGeofencingInterface->resume_geofence(geofence_id, monitor_transition);
-        return JNI_TRUE;
-    } else {
-        ALOGE("Geofence interface not available");
-    }
-    return JNI_FALSE;
-}
-
 template<class T>
 class JavaMethodHelper {
-  public:
-   // Helper function to call setter on a Java object.
-   static void callJavaMethod(
+ public:
+    // Helper function to call setter on a Java object.
+    static void callJavaMethod(
            JNIEnv* env,
            jclass clazz,
            jobject object,
            const char* method_name,
            T value);
 
-  private:
+ private:
     static const char *const signature_;
 };
 
@@ -1045,20 +136,20 @@
 }
 
 class JavaObject {
-  public:
-   JavaObject(JNIEnv* env, const char* class_name);
-   virtual ~JavaObject();
+ public:
+    JavaObject(JNIEnv* env, const char* class_name);
+    virtual ~JavaObject();
 
-   template<class T>
-   void callSetter(const char* method_name, T value);
-   template<class T>
-   void callSetter(const char* method_name, T* value, size_t size);
-   jobject get();
+    template<class T>
+    void callSetter(const char* method_name, T value);
+    template<class T>
+    void callSetter(const char* method_name, T* value, size_t size);
+    jobject get();
 
-  private:
-   JNIEnv* env_;
-   jclass clazz_;
-   jobject object_;
+ private:
+    JNIEnv* env_;
+    jclass clazz_;
+    jobject object_;
 };
 
 JavaObject::JavaObject(JNIEnv* env, const char* class_name) : env_(env) {
@@ -1081,7 +172,7 @@
 void JavaObject::callSetter(
         const char* method_name, uint8_t* value, size_t size) {
     jbyteArray array = env_->NewByteArray(size);
-    env_->SetByteArrayRegion(array, 0, size, (jbyte*) value);
+    env_->SetByteArrayRegion(array, 0, size, reinterpret_cast<jbyte*>(value));
     jmethodID method = env_->GetMethodID(
             clazz_,
             method_name,
@@ -1095,7 +186,6 @@
 }
 
 // Define Java method signatures for all known types.
-
 template<>
 const char *const JavaMethodHelper<uint8_t>::signature_ = "(B)V";
 template<>
@@ -1119,209 +209,460 @@
 
 #define SET(setter, value) object.callSetter("set" # setter, (value))
 
-// If you want to check if a flag is not set, use SET_IF_NOT(FLAG, setter,
-// value) to do that. SET_IF(!FLAG, setter, value) won't compile.
-//
-// This macros generates compilation error if the provided 'flag' is not a
-// single token. For example, 'GNSS_CLOCK_HAS_BIAS' can be accepted, but
-// '!GNSS_CLOCK_HAS_DRIFT' will fail to compile.
-#define SET_IF(flag, setter, value) do { \
-        if (flags & flag) { \
-            JavaObject& name_check_##flag = object; \
-            name_check_##flag.callSetter("set" # setter, (value)); \
-        } \
-    } while (false)
-#define SET_IF_NOT(flag, setter, value) do { \
-        if (!(flags & flag)) { \
-            JavaObject& name_check_##flag = object; \
-            name_check_##flag.callSetter("set" # setter, (value)); \
-        } \
-    } while (false)
+static inline jboolean boolToJbool(bool value) {
+    return value ? JNI_TRUE : JNI_FALSE;
+}
 
-static jobject translate_gps_clock(JNIEnv* env, GpsClock* clock) {
-    static uint32_t discontinuity_count_to_handle_old_clock_type = 0;
-    JavaObject object(env, "android/location/GnssClock");
-    GpsClockFlags flags = clock->flags;
+static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
+    if (env->ExceptionCheck()) {
+        ALOGE("An exception was thrown by callback '%s'.", methodName);
+        LOGE_EX(env);
+        env->ExceptionClear();
+    }
+}
 
-    SET_IF(GPS_CLOCK_HAS_LEAP_SECOND,
-           LeapSecond,
-           static_cast<int32_t>(clock->leap_second));
+/*
+ * GnssCallback class implements the callback methods for IGnss interface.
+ */
+struct GnssCallback : public IGnssCallback {
+    Return<void> gnssLocationCb(
+          const android::hardware::gnss::V1_0::GnssLocation& location) override;
+    Return<void> gnssStatusCb(const IGnssCallback::GnssStatusValue status) override;
+    Return<void> gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) override;
+    Return<void> gnssNmeaCb(int64_t timestamp, const android::hardware::hidl_string& nmea) override;
+    Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
+    Return<void> gnssAcquireWakelockCb() override;
+    Return<void> gnssReleaseWakelockCb() override;
+    Return<void> gnssRequestTimeCb() override;
+    Return<void> gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) override;
 
-    // GnssClock only supports the more effective HW_CLOCK type, so type
-    // handling and documentation complexity has been removed.  To convert the
-    // old GPS_CLOCK types (active only in a limited number of older devices),
-    // the GPS time information is handled as an always discontinuous HW clock,
-    // with the GPS time information put into the full_bias_ns instead - so that
-    // time_ns - full_bias_ns = local estimate of GPS time. Additionally, the
-    // sign of full_bias_ns and bias_ns has flipped between GpsClock &
-    // GnssClock, so that is also handled below.
-    switch (clock->type) {
-      case GPS_CLOCK_TYPE_UNKNOWN:
-        // Clock type unsupported.
-        ALOGE("Unknown clock type provided.");
-        break;
-      case GPS_CLOCK_TYPE_LOCAL_HW_TIME:
-        // Already local hardware time. No need to do anything.
-        break;
-      case GPS_CLOCK_TYPE_GPS_TIME:
-        // GPS time, need to convert.
-        flags |= GPS_CLOCK_HAS_FULL_BIAS;
-        clock->full_bias_ns = clock->time_ns;
-        clock->time_ns = 0;
-        SET(HardwareClockDiscontinuityCount,
-            discontinuity_count_to_handle_old_clock_type++);
-        break;
+    static GnssSvInfo sGnssSvList[static_cast<uint32_t>(
+            android::hardware::gnss::V1_0::GnssMax::SVS_COUNT)];
+    static size_t sGnssSvListSize;
+
+    static const char* sNmeaString;
+    static size_t sNmeaStringLength;
+};
+
+IGnssCallback::GnssSvInfo GnssCallback::sGnssSvList[static_cast<uint32_t>(
+        android::hardware::gnss::V1_0::GnssMax::SVS_COUNT)];
+const char* GnssCallback::sNmeaString = nullptr;
+size_t GnssCallback::sNmeaStringLength = 0;
+size_t GnssCallback::sGnssSvListSize = 0;
+
+Return<void> GnssCallback::gnssLocationCb(
+        const ::android::hardware::gnss::V1_0::GnssLocation& location) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj,
+                        method_reportLocation,
+                        location.gnssLocationFlags,
+                        static_cast<jdouble>(location.latitudeDegrees),
+                        static_cast<jdouble>(location.longitudeDegrees),
+                        static_cast<jdouble>(location.altitudeMeters),
+                        static_cast<jfloat>(location.speedMetersPerSec),
+                        static_cast<jfloat>(location.bearingDegrees),
+                        static_cast<jfloat>(location.accuracyMeters),
+                        static_cast<jlong>(location.timestamp));
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
+}
+
+Return<void> GnssCallback::gnssStatusCb(const IGnssCallback::GnssStatusValue status) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj, method_reportStatus, status);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
+}
+
+Return<void> GnssCallback::gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+    sGnssSvListSize = svStatus.numSvs;
+    if (sGnssSvListSize > static_cast<uint32_t>(
+            android::hardware::gnss::V1_0::GnssMax::SVS_COUNT)) {
+        ALOGD("Too many satellites %zd. Clamps to %u.", sGnssSvListSize,
+              static_cast<uint32_t>(android::hardware::gnss::V1_0::GnssMax::SVS_COUNT));
+        sGnssSvListSize = static_cast<uint32_t>(android::hardware::gnss::V1_0::GnssMax::SVS_COUNT);
     }
 
-    SET(TimeNanos, clock->time_ns);
-    SET_IF(GPS_CLOCK_HAS_TIME_UNCERTAINTY,
-           TimeUncertaintyNanos,
-           clock->time_uncertainty_ns);
-
-    // Definition of sign for full_bias_ns & bias_ns has been changed since N,
-    // so flip signs here.
-    SET_IF(GPS_CLOCK_HAS_FULL_BIAS, FullBiasNanos, -(clock->full_bias_ns));
-    SET_IF(GPS_CLOCK_HAS_BIAS, BiasNanos, -(clock->bias_ns));
-
-    SET_IF(GPS_CLOCK_HAS_BIAS_UNCERTAINTY,
-           BiasUncertaintyNanos,
-           clock->bias_uncertainty_ns);
-    SET_IF(GPS_CLOCK_HAS_DRIFT, DriftNanosPerSecond, clock->drift_nsps);
-    SET_IF(GPS_CLOCK_HAS_DRIFT_UNCERTAINTY,
-           DriftUncertaintyNanosPerSecond,
-           clock->drift_uncertainty_nsps);
-
-    return object.get();
-}
-
-static jobject translate_gnss_clock(JNIEnv* env, GnssClock* clock) {
-    JavaObject object(env, "android/location/GnssClock");
-    GnssClockFlags flags = clock->flags;
-
-    SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND,
-           LeapSecond,
-           static_cast<int32_t>(clock->leap_second));
-    SET(TimeNanos, clock->time_ns);
-    SET_IF(GNSS_CLOCK_HAS_TIME_UNCERTAINTY,
-           TimeUncertaintyNanos,
-           clock->time_uncertainty_ns);
-    SET_IF(GNSS_CLOCK_HAS_FULL_BIAS, FullBiasNanos, clock->full_bias_ns);
-    SET_IF(GNSS_CLOCK_HAS_BIAS, BiasNanos, clock->bias_ns);
-    SET_IF(GNSS_CLOCK_HAS_BIAS_UNCERTAINTY,
-           BiasUncertaintyNanos,
-           clock->bias_uncertainty_ns);
-    SET_IF(GNSS_CLOCK_HAS_DRIFT, DriftNanosPerSecond, clock->drift_nsps);
-    SET_IF(GNSS_CLOCK_HAS_DRIFT_UNCERTAINTY,
-           DriftUncertaintyNanosPerSecond,
-           clock->drift_uncertainty_nsps);
-
-    SET(HardwareClockDiscontinuityCount, clock->hw_clock_discontinuity_count);
-
-    return object.get();
-}
-
-static jobject translate_gps_measurement(JNIEnv* env,
-                                         GpsMeasurement* measurement) {
-    JavaObject object(env, "android/location/GnssMeasurement");
-    GpsMeasurementFlags flags = measurement->flags;
-    SET(Svid, static_cast<int32_t>(measurement->prn));
-    if (measurement->prn >= 1 && measurement->prn <= 32) {
-        SET(ConstellationType, static_cast<int32_t>(GNSS_CONSTELLATION_GPS));
-    } else {
-        ALOGD("Unknown constellation type with Svid = %d.", measurement->prn);
-        SET(ConstellationType,
-            static_cast<int32_t>(GNSS_CONSTELLATION_UNKNOWN));
+    // Copy GNSS SV info into sGnssSvList, if any.
+    if (svStatus.numSvs > 0) {
+        memcpy(sGnssSvList, svStatus.gnssSvList.data(), sizeof(GnssSvInfo) * sGnssSvListSize);
     }
-    SET(TimeOffsetNanos, measurement->time_offset_ns);
-    SET(State, static_cast<int32_t>(measurement->state));
-    SET(ReceivedSvTimeNanos, measurement->received_gps_tow_ns);
-    SET(ReceivedSvTimeUncertaintyNanos,
-        measurement->received_gps_tow_uncertainty_ns);
-    SET(Cn0DbHz, measurement->c_n0_dbhz);
-    SET(PseudorangeRateMetersPerSecond, measurement->pseudorange_rate_mps);
-    SET(PseudorangeRateUncertaintyMetersPerSecond,
-        measurement->pseudorange_rate_uncertainty_mps);
-    SET(AccumulatedDeltaRangeState,
-        static_cast<int32_t>(measurement->accumulated_delta_range_state));
-    SET(AccumulatedDeltaRangeMeters, measurement->accumulated_delta_range_m);
-    SET(AccumulatedDeltaRangeUncertaintyMeters,
-        measurement->accumulated_delta_range_uncertainty_m);
-    SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY,
-           CarrierFrequencyHz,
-           measurement->carrier_frequency_hz);
-    SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_CYCLES,
-           CarrierCycles,
-           measurement->carrier_cycles);
-    SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE,
-           CarrierPhase,
-           measurement->carrier_phase);
-    SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY,
-           CarrierPhaseUncertainty,
-           measurement->carrier_phase_uncertainty);
-    SET(MultipathIndicator,
-        static_cast<int32_t>(measurement->multipath_indicator));
-    SET_IF(GNSS_MEASUREMENT_HAS_SNR, SnrInDb, measurement->snr_db);
 
-    return object.get();
+    env->CallVoidMethod(mCallbacksObj, method_reportSvStatus);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
 }
 
-static jobject translate_gnss_measurement(JNIEnv* env,
-                                          GnssMeasurement* measurement) {
+Return<void> GnssCallback::gnssNmeaCb(
+    int64_t timestamp, const ::android::hardware::hidl_string& nmea) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    /*
+     * The Java code will call back to read these values.
+     * We do this to avoid creating unnecessary String objects.
+     */
+    sNmeaString = nmea.c_str();
+    sNmeaStringLength = nmea.size();
+
+    env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
+}
+
+Return<void> GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) {
+    ALOGD("%s: %du\n", __func__, capabilities);
+
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
+}
+
+Return<void> GnssCallback::gnssAcquireWakelockCb() {
+    acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
+    return Void();
+}
+
+Return<void> GnssCallback::gnssReleaseWakelockCb() {
+    release_wake_lock(WAKE_LOCK_NAME);
+    return Void();
+}
+
+Return<void> GnssCallback::gnssRequestTimeCb() {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
+}
+
+Return<void> GnssCallback::gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) {
+    ALOGD("%s: yearOfHw=%d\n", __func__, info.yearOfHw);
+
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj, method_setGnssYearOfHardware,
+                        info.yearOfHw);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
+}
+
+class GnssXtraCallback : public IGnssXtraCallback {
+    Return<void> downloadRequestCb() override;
+};
+
+/*
+ * GnssXtraCallback class implements the callback methods for the IGnssXtra
+ * interface.
+ */
+Return<void> GnssXtraCallback::downloadRequestCb() {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj, method_xtraDownloadRequest);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
+}
+
+/*
+ * GnssGeofenceCallback class implements the callback methods for the
+ * IGnssGeofence interface.
+ */
+struct GnssGeofenceCallback : public IGnssGeofenceCallback {
+    // Methods from ::android::hardware::gps::V1_0::IGnssGeofenceCallback follow.
+    Return<void> gnssGeofenceTransitionCb(
+            int32_t geofenceId,
+            const android::hardware::gnss::V1_0::GnssLocation& location,
+            GeofenceTransition transition,
+            hardware::gnss::V1_0::GnssUtcTime timestamp) override;
+    Return<void> gnssGeofenceStatusCb(
+            GeofenceAvailability status,
+            const android::hardware::gnss::V1_0::GnssLocation& location) override;
+    Return<void> gnssGeofenceAddCb(int32_t geofenceId,
+                                   GeofenceStatus status) override;
+    Return<void> gnssGeofenceRemoveCb(int32_t geofenceId,
+                                      GeofenceStatus status) override;
+    Return<void> gnssGeofencePauseCb(int32_t geofenceId,
+                                     GeofenceStatus status) override;
+    Return<void> gnssGeofenceResumeCb(int32_t geofenceId,
+                                      GeofenceStatus status) override;
+};
+
+Return<void> GnssGeofenceCallback::gnssGeofenceTransitionCb(
+        int32_t geofenceId,
+        const android::hardware::gnss::V1_0::GnssLocation& location,
+        GeofenceTransition transition,
+        hardware::gnss::V1_0::GnssUtcTime timestamp) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+    env->CallVoidMethod(mCallbacksObj,
+                        method_reportGeofenceTransition,
+                        geofenceId,
+                        location.gnssLocationFlags,
+                        static_cast<jdouble>(location.latitudeDegrees),
+                        static_cast<jdouble>(location.longitudeDegrees),
+                        static_cast<jdouble>(location.altitudeMeters),
+                        static_cast<jfloat>(location.speedMetersPerSec),
+                        static_cast<jfloat>(location.bearingDegrees),
+                        static_cast<jfloat>(location.accuracyMeters),
+                        static_cast<jlong>(location.timestamp),
+                        transition,
+                        timestamp);
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
+}
+
+Return<void> GnssGeofenceCallback::gnssGeofenceStatusCb(
+        GeofenceAvailability status,
+        const android::hardware::gnss::V1_0::GnssLocation& location) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj,
+                        method_reportGeofenceStatus,
+                        status,
+                        location.gnssLocationFlags,
+                        static_cast<jdouble>(location.latitudeDegrees),
+                        static_cast<jdouble>(location.longitudeDegrees),
+                        static_cast<jdouble>(location.altitudeMeters),
+                        static_cast<jfloat>(location.speedMetersPerSec),
+                        static_cast<jfloat>(location.bearingDegrees),
+                        static_cast<jfloat>(location.accuracyMeters),
+                        static_cast<jlong>(location.timestamp));
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
+}
+
+Return<void> GnssGeofenceCallback::gnssGeofenceAddCb(int32_t geofenceId,
+                                                    GeofenceStatus status) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (status != IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS) {
+        ALOGE("%s: Error in adding a Geofence: %d\n", __func__, status);
+    }
+
+    env->CallVoidMethod(mCallbacksObj,
+                        method_reportGeofenceAddStatus,
+                        geofenceId,
+                        status);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
+}
+
+Return<void> GnssGeofenceCallback::gnssGeofenceRemoveCb(int32_t geofenceId,
+                                                       GeofenceStatus status) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (status != IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS) {
+        ALOGE("%s: Error in removing a Geofence: %d\n", __func__, status);
+    }
+
+    env->CallVoidMethod(mCallbacksObj,
+                        method_reportGeofenceRemoveStatus,
+                        geofenceId, status);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
+}
+
+Return<void> GnssGeofenceCallback::gnssGeofencePauseCb(int32_t geofenceId,
+                                                      GeofenceStatus status) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (status != IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS) {
+        ALOGE("%s: Error in pausing Geofence: %d\n", __func__, status);
+    }
+
+    env->CallVoidMethod(mCallbacksObj,
+                        method_reportGeofencePauseStatus,
+                        geofenceId, status);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
+}
+
+Return<void> GnssGeofenceCallback::gnssGeofenceResumeCb(int32_t geofenceId,
+                                                       GeofenceStatus status) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (status != IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS) {
+        ALOGE("%s: Error in resuming Geofence: %d\n", __func__, status);
+    }
+
+    env->CallVoidMethod(mCallbacksObj,
+                        method_reportGeofenceResumeStatus,
+                        geofenceId, status);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
+}
+
+/*
+ * GnssNavigationMessageCallback interface implements the callback methods
+ * required by the IGnssNavigationMessage interface.
+ */
+struct GnssNavigationMessageCallback : public IGnssNavigationMessageCallback {
+  /*
+   * Methods from ::android::hardware::gps::V1_0::IGnssNavigationMessageCallback
+   * follow.
+   */
+  Return<void> gnssNavigationMessageCb(
+          const IGnssNavigationMessageCallback::GnssNavigationMessage& message) override;
+};
+
+Return<void> GnssNavigationMessageCallback::gnssNavigationMessageCb(
+        const IGnssNavigationMessageCallback::GnssNavigationMessage& message) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+    size_t dataLength = message.data.size();
+
+    std::vector<uint8_t> navigationData = message.data;
+    uint8_t* data = &(navigationData[0]);
+    if (dataLength == 0 || data == NULL) {
+      ALOGE("Invalid Navigation Message found: data=%p, length=%zd", data,
+            dataLength);
+      return Void();
+    }
+
+    JavaObject object(env, "android/location/GnssNavigationMessage");
+    SET(Type, static_cast<int32_t>(message.type));
+    SET(Svid, static_cast<int32_t>(message.svid));
+    SET(MessageId, static_cast<int32_t>(message.messageId));
+    SET(SubmessageId, static_cast<int32_t>(message.submessageId));
+    object.callSetter("setData", data, dataLength);
+    SET(Status, static_cast<int32_t>(message.status));
+
+    jobject navigationMessage = object.get();
+    env->CallVoidMethod(mCallbacksObj,
+                        method_reportNavigationMessages,
+                        navigationMessage);
+    env->DeleteLocalRef(navigationMessage);
+    return Void();
+}
+
+/*
+ * GnssMeasurementCallback implements the callback methods required for the
+ * GnssMeasurement interface.
+ */
+struct GnssMeasurementCallback : public IGnssMeasurementCallback {
+    Return<void> GnssMeasurementCb(const IGnssMeasurementCallback::GnssData& data);
+ private:
+    jobject translateGnssMeasurement(
+            JNIEnv* env, const IGnssMeasurementCallback::GnssMeasurement* measurement);
+    jobject translateGnssClock(
+            JNIEnv* env, const IGnssMeasurementCallback::GnssClock* clock);
+    jobjectArray translateGnssMeasurements(
+            JNIEnv* env,
+            const IGnssMeasurementCallback::GnssMeasurement* measurements,
+            size_t count);
+    void setMeasurementData(JNIEnv* env, jobject clock, jobjectArray measurementArray);
+};
+
+
+Return<void> GnssMeasurementCallback::GnssMeasurementCb(
+        const IGnssMeasurementCallback::GnssData& data) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+    jobject clock;
+    jobjectArray measurementArray;
+
+    clock = translateGnssClock(env, &data.clock);
+    measurementArray = translateGnssMeasurements(
+        env, data.measurements.data(), data.measurementCount);
+    setMeasurementData(env, clock, measurementArray);
+
+    env->DeleteLocalRef(clock);
+    env->DeleteLocalRef(measurementArray);
+    return Void();
+}
+
+jobject GnssMeasurementCallback::translateGnssMeasurement(
+        JNIEnv* env, const IGnssMeasurementCallback::GnssMeasurement* measurement) {
     JavaObject object(env, "android/location/GnssMeasurement");
 
-    GnssMeasurementFlags flags = measurement->flags;
+    uint32_t flags = static_cast<uint32_t>(measurement->flags);
 
     SET(Svid, static_cast<int32_t>(measurement->svid));
     SET(ConstellationType, static_cast<int32_t>(measurement->constellation));
-    SET(TimeOffsetNanos, measurement->time_offset_ns);
+    SET(TimeOffsetNanos, measurement->timeOffsetNs);
     SET(State, static_cast<int32_t>(measurement->state));
-    SET(ReceivedSvTimeNanos, measurement->received_sv_time_in_ns);
+    SET(ReceivedSvTimeNanos, measurement->receivedSvTimeInNs);
     SET(ReceivedSvTimeUncertaintyNanos,
-        measurement->received_sv_time_uncertainty_in_ns);
-    SET(Cn0DbHz, measurement->c_n0_dbhz);
-    SET(PseudorangeRateMetersPerSecond, measurement->pseudorange_rate_mps);
+        measurement->receivedSvTimeUncertaintyInNs);
+    SET(Cn0DbHz, measurement->cN0DbHz);
+    SET(PseudorangeRateMetersPerSecond, measurement->pseudorangeRateMps);
     SET(PseudorangeRateUncertaintyMetersPerSecond,
-        measurement->pseudorange_rate_uncertainty_mps);
+        measurement->pseudorangeRateUncertaintyMps);
     SET(AccumulatedDeltaRangeState,
-        static_cast<int32_t>(measurement->accumulated_delta_range_state));
-    SET(AccumulatedDeltaRangeMeters, measurement->accumulated_delta_range_m);
+        (static_cast<int32_t>(measurement->accumulatedDeltaRangeState)));
+    SET(AccumulatedDeltaRangeMeters, measurement->accumulatedDeltaRangeM);
     SET(AccumulatedDeltaRangeUncertaintyMeters,
-        measurement->accumulated_delta_range_uncertainty_m);
-    SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY,
-           CarrierFrequencyHz,
-           measurement->carrier_frequency_hz);
-    SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_CYCLES,
-           CarrierCycles,
-           measurement->carrier_cycles);
-    SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE,
-           CarrierPhase,
-           measurement->carrier_phase);
-    SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY,
-           CarrierPhaseUncertainty,
-           measurement->carrier_phase_uncertainty);
-    SET(MultipathIndicator,
-        static_cast<int32_t>(measurement->multipath_indicator));
-    SET_IF(GNSS_MEASUREMENT_HAS_SNR, SnrInDb, measurement->snr_db);
+        measurement->accumulatedDeltaRangeUncertaintyM);
+
+    if (flags & static_cast<uint32_t>(GnssMeasurementFlags::HAS_CARRIER_FREQUENCY)) {
+        SET(CarrierFrequencyHz, measurement->carrierFrequencyHz);
+    }
+
+    if (flags & static_cast<uint32_t>(GnssMeasurementFlags::HAS_CARRIER_PHASE)) {
+        SET(CarrierPhase, measurement->carrierPhase);
+    }
+
+    if (flags & static_cast<uint32_t>(GnssMeasurementFlags::HAS_CARRIER_PHASE_UNCERTAINTY)) {
+        SET(CarrierPhaseUncertainty, measurement->carrierPhaseUncertainty);
+    }
+
+    SET(MultipathIndicator, static_cast<int32_t>(measurement->multipathIndicator));
+
+    if (flags & static_cast<uint32_t>(GnssMeasurementFlags::HAS_SNR)) {
+        SET(SnrInDb, measurement->snrDb);
+    }
 
     return object.get();
 }
 
-static jobjectArray translate_gps_measurements(JNIEnv* env,
-                                               GpsMeasurement* measurements,
-                                               size_t count) {
+jobject GnssMeasurementCallback::translateGnssClock(
+       JNIEnv* env, const IGnssMeasurementCallback::GnssClock* clock) {
+    JavaObject object(env, "android/location/GnssClock");
+
+    uint32_t flags = static_cast<uint32_t>(clock->gnssClockFlags);
+    if (flags & static_cast<uint32_t>(GnssClockFlags::HAS_LEAP_SECOND)) {
+        SET(LeapSecond, static_cast<int32_t>(clock->leapSecond));
+    }
+
+    if (flags & static_cast<uint32_t>(GnssClockFlags::HAS_TIME_UNCERTAINTY)) {
+        SET(TimeUncertaintyNanos, clock->timeUncertaintyNs);
+    }
+
+    if (flags & static_cast<uint32_t>(GnssClockFlags::HAS_FULL_BIAS)) {
+        SET(FullBiasNanos, clock->fullBiasNs);
+    }
+
+    if (flags & static_cast<uint32_t>(GnssClockFlags::HAS_BIAS)) {
+        SET(BiasNanos, clock->biasNs);
+    }
+
+    if (flags & static_cast<uint32_t>(GnssClockFlags::HAS_BIAS_UNCERTAINTY)) {
+        SET(BiasUncertaintyNanos, clock->biasUncertaintyNs);
+    }
+
+    if (flags & static_cast<uint32_t>(GnssClockFlags::HAS_DRIFT)) {
+        SET(DriftNanosPerSecond, clock->driftNsps);
+    }
+
+    if (flags & static_cast<uint32_t>(GnssClockFlags::HAS_DRIFT_UNCERTAINTY)) {
+        SET(DriftUncertaintyNanosPerSecond, clock->driftUncertaintyNsps);
+    }
+
+    SET(TimeNanos, clock->timeNs);
+    SET(HardwareClockDiscontinuityCount, clock->hwClockDiscontinuityCount);
+
+    return object.get();
+}
+
+jobjectArray GnssMeasurementCallback::translateGnssMeasurements(JNIEnv* env,
+                                       const IGnssMeasurementCallback::GnssMeasurement*
+                                       measurements, size_t count) {
     if (count == 0) {
         return NULL;
     }
 
-    jclass gnssMeasurementClass = env->FindClass(
-            "android/location/GnssMeasurement");
+    jclass gnssMeasurementClass = env->FindClass("android/location/GnssMeasurement");
     jobjectArray gnssMeasurementArray = env->NewObjectArray(
             count,
             gnssMeasurementClass,
             NULL /* initialElement */);
 
     for (uint16_t i = 0; i < count; ++i) {
-        jobject gnssMeasurement = translate_gps_measurement(
+        jobject gnssMeasurement = translateGnssMeasurement(
             env,
             &measurements[i]);
         env->SetObjectArrayElement(gnssMeasurementArray, i, gnssMeasurement);
@@ -1332,130 +673,789 @@
     return gnssMeasurementArray;
 }
 
-static jobjectArray translate_gnss_measurements(JNIEnv* env,
-                                                GnssMeasurement* measurements,
-                                                size_t count) {
-    if (count == 0) {
-        return NULL;
-    }
+void GnssMeasurementCallback::setMeasurementData(JNIEnv* env, jobject clock,
+                             jobjectArray measurementArray) {
+    jclass gnssMeasurementsEventClass =
+            env->FindClass("android/location/GnssMeasurementsEvent");
+    jmethodID gnssMeasurementsEventCtor =
+            env->GetMethodID(
+                    gnssMeasurementsEventClass,
+                    "<init>",
+                    "(Landroid/location/GnssClock;[Landroid/location/GnssMeasurement;)V");
 
-    jclass gnssMeasurementClass = env->FindClass(
-            "android/location/GnssMeasurement");
-    jobjectArray gnssMeasurementArray = env->NewObjectArray(
-            count,
-            gnssMeasurementClass,
-            NULL /* initialElement */);
+    jobject gnssMeasurementsEvent = env->NewObject(gnssMeasurementsEventClass,
+                                                   gnssMeasurementsEventCtor,
+                                                   clock,
+                                                   measurementArray);
 
-    for (uint16_t i = 0; i < count; ++i) {
-        jobject gnssMeasurement = translate_gnss_measurement(
-            env,
-            &measurements[i]);
-        env->SetObjectArrayElement(gnssMeasurementArray, i, gnssMeasurement);
-        env->DeleteLocalRef(gnssMeasurement);
-    }
-
-    env->DeleteLocalRef(gnssMeasurementClass);
-    return gnssMeasurementArray;
-}
-
-static void set_measurement_data(JNIEnv *env,
-                                 jobject clock,
-                                 jobjectArray measurementArray) {
-    jclass gnssMeasurementsEventClass = env->FindClass(
-            "android/location/GnssMeasurementsEvent");
-    jmethodID gnssMeasurementsEventCtor = env->GetMethodID(
-        gnssMeasurementsEventClass,
-        "<init>",
-        "(Landroid/location/GnssClock;[Landroid/location/GnssMeasurement;)V");
-
-    jobject gnssMeasurementsEvent = env->NewObject(
-        gnssMeasurementsEventClass,
-        gnssMeasurementsEventCtor,
-        clock,
-        measurementArray);
-    env->CallVoidMethod(mCallbacksObj,
-                        method_reportMeasurementData,
-                        gnssMeasurementsEvent);
+    env->CallVoidMethod(mCallbacksObj, method_reportMeasurementData,
+                      gnssMeasurementsEvent);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
     env->DeleteLocalRef(gnssMeasurementsEventClass);
     env->DeleteLocalRef(gnssMeasurementsEvent);
 }
 
-static void measurement_callback(GpsData* data) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    if (data == NULL) {
-        ALOGE("Invalid data provided to gps_measurement_callback");
-        return;
-    }
-    if (data->size != sizeof(GpsData)) {
-        ALOGE("Invalid GpsData size found in gps_measurement_callback, "
-              "size=%zd",
-              data->size);
-        return;
-    }
-
-    jobject clock;
-    jobjectArray measurementArray;
-    clock = translate_gps_clock(env, &data->clock);
-    measurementArray = translate_gps_measurements(
-            env, data->measurements, data->measurement_count);
-    set_measurement_data(env, clock, measurementArray);
-
-    env->DeleteLocalRef(clock);
-    env->DeleteLocalRef(measurementArray);
-}
-
-static void gnss_measurement_callback(GnssData* data) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    if (data == NULL) {
-        ALOGE("Invalid data provided to gps_measurement_callback");
-        return;
-    }
-    if (data->size != sizeof(GnssData)) {
-        ALOGE("Invalid GnssData size found in gnss_measurement_callback, "
-              "size=%zd",
-              data->size);
-        return;
-    }
-
-    jobject clock;
-    jobjectArray measurementArray;
-    clock = translate_gnss_clock(env, &data->clock);
-    measurementArray = translate_gnss_measurements(
-            env, data->measurements, data->measurement_count);
-    set_measurement_data(env, clock, measurementArray);
-
-    env->DeleteLocalRef(clock);
-    env->DeleteLocalRef(measurementArray);
-}
-
-GpsMeasurementCallbacks sGpsMeasurementCallbacks = {
-    sizeof(GpsMeasurementCallbacks),
-    measurement_callback,
-    gnss_measurement_callback,
+/*
+ * GnssNiCallback implements callback methods required by the IGnssNi interface.
+ */
+struct GnssNiCallback : public IGnssNiCallback {
+    Return<void> niNotifyCb(const IGnssNiCallback::GnssNiNotification& notification)
+            override;
 };
 
+Return<void> GnssNiCallback::niNotifyCb(
+        const IGnssNiCallback::GnssNiNotification& notification) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jstring requestorId = env->NewStringUTF(notification.requestorId.c_str());
+    jstring text = env->NewStringUTF(notification.notificationMessage.c_str());
+
+    if (requestorId && text) {
+        env->CallVoidMethod(mCallbacksObj, method_reportNiNotification,
+                            notification.notificationId, notification.niType,
+                            notification.notifyFlags, notification.timeoutSec,
+                            notification.defaultResponse, requestorId, text,
+                            notification.requestorIdEncoding,
+                            notification.notificationIdEncoding);
+    } else {
+        ALOGE("%s: OOM Error\n", __func__);
+    }
+
+    if (requestorId) {
+        env->DeleteLocalRef(requestorId);
+    }
+
+    if (text) {
+        env->DeleteLocalRef(text);
+    }
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
+}
+
+/*
+ * AGnssCallback implements callback methods required by the IAGnss interface.
+ */
+struct AGnssCallback : public IAGnssCallback {
+    // Methods from ::android::hardware::gps::V1_0::IAGnssCallback follow.
+    Return<void> agnssStatusIpV6Cb(
+      const IAGnssCallback::AGnssStatusIpV6& agps_status) override;
+
+    Return<void> agnssStatusIpV4Cb(
+      const IAGnssCallback::AGnssStatusIpV4& agps_status) override;
+ private:
+    jbyteArray convertToIpV4(uint32_t ip);
+};
+
+Return<void> AGnssCallback::agnssStatusIpV6Cb(
+        const IAGnssCallback::AGnssStatusIpV6& agps_status) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jbyteArray byteArray = NULL;
+    bool isSupported = false;
+
+    byteArray = env->NewByteArray(16);
+    if (byteArray != NULL) {
+        env->SetByteArrayRegion(byteArray, 0, 16,
+                                (const jbyte*)(agps_status.ipV6Addr.data()));
+        isSupported = true;
+    } else {
+        ALOGE("Unable to allocate byte array for IPv6 address.");
+    }
+
+    IF_ALOGD() {
+        // log the IP for reference in case there is a bogus value pushed by HAL
+        char str[INET6_ADDRSTRLEN];
+        inet_ntop(AF_INET6, agps_status.ipV6Addr.data(), str, INET6_ADDRSTRLEN);
+        ALOGD("AGPS IP is v6: %s", str);
+    }
+
+    jsize byteArrayLength = byteArray != NULL ? env->GetArrayLength(byteArray) : 0;
+    ALOGV("Passing AGPS IP addr: size %d", byteArrayLength);
+    env->CallVoidMethod(mCallbacksObj, method_reportAGpsStatus,
+                        agps_status.type, agps_status.status, byteArray);
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+
+    if (byteArray) {
+        env->DeleteLocalRef(byteArray);
+    }
+
+    return Void();
+}
+
+Return<void> AGnssCallback::agnssStatusIpV4Cb(
+        const IAGnssCallback::AGnssStatusIpV4& agps_status) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jbyteArray byteArray = NULL;
+
+    uint32_t ipAddr = agps_status.ipV4Addr;
+    byteArray = convertToIpV4(ipAddr);
+
+    IF_ALOGD() {
+        /*
+         * log the IP for reference in case there is a bogus value pushed by
+         * HAL.
+         */
+        char str[INET_ADDRSTRLEN];
+        inet_ntop(AF_INET, &ipAddr, str, INET_ADDRSTRLEN);
+        ALOGD("AGPS IP is v4: %s", str);
+    }
+
+    jsize byteArrayLength =
+      byteArray != NULL ? env->GetArrayLength(byteArray) : 0;
+    ALOGV("Passing AGPS IP addr: size %d", byteArrayLength);
+    env->CallVoidMethod(mCallbacksObj, method_reportAGpsStatus,
+                      agps_status.type, agps_status.status, byteArray);
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+
+    if (byteArray) {
+        env->DeleteLocalRef(byteArray);
+    }
+    return Void();
+}
+
+jbyteArray AGnssCallback::convertToIpV4(uint32_t ip) {
+    if (INADDR_NONE == ip) {
+        return NULL;
+    }
+
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jbyteArray byteArray = env->NewByteArray(4);
+    if (byteArray == NULL) {
+        ALOGE("Unable to allocate byte array for IPv4 address");
+        return NULL;
+    }
+
+    jbyte ipv4[4];
+    ALOGV("Converting IPv4 address byte array (net_order) %x", ip);
+    memcpy(ipv4, &ip, sizeof(ipv4));
+    env->SetByteArrayRegion(byteArray, 0, 4, (const jbyte*)ipv4);
+    return byteArray;
+}
+
+/*
+ * AGnssRilCallback implements the callback methods required by the AGnssRil
+ * interface.
+ */
+struct AGnssRilCallback : IAGnssRilCallback {
+    Return<void> requestSetIdCb(IAGnssRilCallback::ID setIdFlag) override;
+    Return<void> requestRefLocCb() override;
+};
+
+Return<void> AGnssRilCallback::requestSetIdCb(IAGnssRilCallback::ID setIdFlag) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj, method_requestSetID, setIdFlag);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
+}
+
+Return<void> AGnssRilCallback::requestRefLocCb() {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj, method_requestRefLocation);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
+}
+
+static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
+    method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
+    method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
+    method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
+    method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II[B)V");
+    method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
+    method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
+    method_setGnssYearOfHardware = env->GetMethodID(clazz, "setGnssYearOfHardware", "(I)V");
+    method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
+    method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification",
+            "(IIIIILjava/lang/String;Ljava/lang/String;II)V");
+    method_requestRefLocation = env->GetMethodID(clazz, "requestRefLocation", "()V");
+    method_requestSetID = env->GetMethodID(clazz, "requestSetID", "(I)V");
+    method_requestUtcTime = env->GetMethodID(clazz, "requestUtcTime", "()V");
+    method_reportGeofenceTransition = env->GetMethodID(clazz, "reportGeofenceTransition",
+            "(IIDDDFFFJIJ)V");
+    method_reportGeofenceStatus = env->GetMethodID(clazz, "reportGeofenceStatus",
+            "(IIDDDFFFJ)V");
+    method_reportGeofenceAddStatus = env->GetMethodID(clazz, "reportGeofenceAddStatus",
+            "(II)V");
+    method_reportGeofenceRemoveStatus = env->GetMethodID(clazz, "reportGeofenceRemoveStatus",
+            "(II)V");
+    method_reportGeofenceResumeStatus = env->GetMethodID(clazz, "reportGeofenceResumeStatus",
+            "(II)V");
+    method_reportGeofencePauseStatus = env->GetMethodID(clazz, "reportGeofencePauseStatus",
+            "(II)V");
+    method_reportMeasurementData = env->GetMethodID(
+            clazz,
+            "reportMeasurementData",
+            "(Landroid/location/GnssMeasurementsEvent;)V");
+    method_reportNavigationMessages = env->GetMethodID(
+            clazz,
+            "reportNavigationMessage",
+            "(Landroid/location/GnssNavigationMessage;)V");
+
+    // TODO(b/31632518)
+    gnssHal = IGnss::getService("gnss");
+    if (gnssHal != nullptr) {
+        auto result = gnssHal->getExtensionXtra([](const sp<IGnssXtra>& xtraIface) {
+            gnssXtraIface = xtraIface;
+        });
+
+        if (!result.getStatus().isOk()) {
+            ALOGD("Unable to get a handle to Xtra");
+        }
+
+        result = gnssHal->getExtensionAGnssRil([](const sp<IAGnssRil>& rilIface) {
+            agnssRilIface = rilIface;
+        });
+
+        if (!result.getStatus().isOk()) {
+            ALOGD("Unable to get a handle to AGnssRil");
+        }
+
+        result = gnssHal->getExtensionAGnss([](const sp<IAGnss>& assistedGnssIface) {
+            agnssIface = assistedGnssIface;
+        });
+
+        if (!result.getStatus().isOk()) {
+            ALOGD("Unable to get a handle to AGnss");
+        }
+
+        result = gnssHal->getExtensionGnssNavigationMessage(
+                [](const sp<IGnssNavigationMessage>& navigationMessageIface) {
+            gnssNavigationMessageIface = navigationMessageIface;
+        });
+
+        if (!result.getStatus().isOk()) {
+            ALOGD("Unable to get a handle to GnssNavigationMessage");
+        }
+
+        result = gnssHal->getExtensionGnssMeasurement([](
+                const sp<IGnssMeasurement>& measurementIface) {
+            gnssMeasurementIface = measurementIface;
+        });
+        if (!result.getStatus().isOk()) {
+            ALOGD("Unable to get a handle to GnssMeasurement");
+        }
+
+        result = gnssHal->getExtensionGnssDebug([](const sp<IGnssDebug>& debugIface) {
+            gnssDebugIface = debugIface;
+        });
+        if (!result.getStatus().isOk()) {
+            ALOGD("Unable to get a handle to GnssDebug");
+        }
+
+        result = gnssHal->getExtensionGnssNi([](const sp<IGnssNi>& niIface) {
+            gnssNiIface = niIface;
+        });
+        if (!result.getStatus().isOk()) {
+            ALOGD("Unable to get a handle to GnssNi");
+        }
+
+        result = gnssHal->getExtensionGnssConfiguration([](const sp<IGnssConfiguration>& configIface) {
+            gnssConfigurationIface = configIface;
+        });
+        if (!result.getStatus().isOk()) {
+            ALOGD("Unable to get a handle to GnssConfiguration");
+        }
+
+        result = gnssHal->getExtensionGnssGeofencing([](const sp<IGnssGeofencing>& geofenceIface) {
+            gnssGeofencingIface = geofenceIface;
+        });
+        if (!result.getStatus().isOk()) {
+            ALOGD("Unable to get a handle to GnssGeofencing");
+        }
+
+    } else {
+      ALOGE("Unable to get GPS service\n");
+    }
+    ProcessState::self()->setThreadPoolMaxThreadCount(0);
+    ProcessState::self()->startThreadPool();
+}
+
+static jboolean android_location_GnssLocationProvider_is_supported(
+        JNIEnv* /* env */, jclass /* clazz */) {
+    return (gnssHal != nullptr) ?  JNI_TRUE : JNI_FALSE;
+}
+
+static jboolean android_location_GnssLocationProvider_is_agps_ril_supported(
+        JNIEnv* /* env */, jclass /* clazz */) {
+    return (agnssRilIface != nullptr) ? JNI_TRUE : JNI_FALSE;
+}
+
+static jboolean android_location_gpsLocationProvider_is_gnss_configuration_supported(
+        JNIEnv* /* env */, jclass /* jclazz */) {
+    return (gnssConfigurationIface != nullptr) ? JNI_TRUE : JNI_FALSE;
+}
+
+static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject obj) {
+    /*
+     * This must be set before calling into the HAL library.
+     */
+    if (!mCallbacksObj)
+        mCallbacksObj = env->NewGlobalRef(obj);
+
+    sp<IGnssCallback> gnssCbIface = new GnssCallback();
+    /*
+     * Fail if the main interface fails to initialize
+     */
+    if (gnssHal == nullptr) {
+        ALOGE("Unable to Initialize GNSS HAL\n");
+        return JNI_FALSE;
+    }
+
+    auto result = gnssHal->setCallback(gnssCbIface);
+    if ((!result) || (!result.getStatus().isOk())) {
+        ALOGE("SetCallback for Gnss Interface fails\n");
+        return JNI_FALSE;
+    }
+
+    sp<IGnssXtraCallback> gnssXtraCbIface = new GnssXtraCallback();
+    if (gnssXtraIface == nullptr) {
+        ALOGE("Unable to initialize GNSS Xtra interface\n");
+    }
+
+    result = gnssXtraIface->setCallback(gnssXtraCbIface);
+    if ((!result) || (!result.getStatus().isOk())) {
+        gnssXtraIface = nullptr;
+        ALOGE("SetCallback for Gnss Xtra Interface fails\n");
+    }
+
+    sp<IAGnssCallback> aGnssCbIface = new AGnssCallback();
+    if (agnssIface != nullptr) {
+        agnssIface->setCallback(aGnssCbIface);
+    } else {
+        ALOGE("Unable to Initialize AGnss interface\n");
+    }
+
+    sp<IGnssGeofenceCallback> gnssGeofencingCbIface = new GnssGeofenceCallback();
+    if (gnssGeofencingIface != nullptr) {
+      gnssGeofencingIface->setCallback(gnssGeofencingCbIface);
+    } else {
+        ALOGE("Unable to initialize GNSS Geofencing interface\n");
+    }
+
+    sp<IGnssNiCallback> gnssNiCbIface = new GnssNiCallback();
+    if (gnssNiCbIface != nullptr) {
+        gnssNiIface->setCallback(gnssNiCbIface);
+    } else {
+        ALOGE("Unable to initialize GNSS NI interface\n");
+    }
+
+    return JNI_TRUE;
+}
+
+static void android_location_GnssLocationProvider_cleanup(JNIEnv* /* env */, jobject /* obj */) {
+    if (gnssHal != nullptr) {
+        gnssHal->cleanup();
+    }
+}
+
+static jboolean android_location_GnssLocationProvider_set_position_mode(JNIEnv* /* env */,
+        jobject /* obj */, jint mode, jint recurrence, jint min_interval, jint preferred_accuracy,
+        jint preferred_time) {
+    if (gnssHal != nullptr) {
+        auto result = gnssHal->setPositionMode(static_cast<IGnss::GnssPositionMode>(mode),
+                                     static_cast<IGnss::GnssPositionRecurrence>(recurrence),
+                                     min_interval,
+                                     preferred_accuracy,
+                                     preferred_time);
+        if (!result.getStatus().isOk()) {
+            ALOGE("%s: GNSS setPositionMode failed\n", __func__);
+            return JNI_FALSE;
+        } else {
+            return result;
+        }
+    } else {
+        return JNI_FALSE;
+    }
+}
+
+static jboolean android_location_GnssLocationProvider_start(JNIEnv* /* env */, jobject /* obj */) {
+    if (gnssHal != nullptr) {
+        auto result = gnssHal->start();
+        if (!result.getStatus().isOk()) {
+            return JNI_FALSE;
+        } else {
+            return result;
+        }
+    } else {
+        return JNI_FALSE;
+    }
+}
+
+static jboolean android_location_GnssLocationProvider_stop(JNIEnv* /* env */, jobject /* obj */) {
+    if (gnssHal != nullptr) {
+        auto result = gnssHal->stop();
+        if (!result.getStatus().isOk()) {
+            return JNI_FALSE;
+        } else {
+            return result;
+        }
+    } else {
+        return JNI_FALSE;
+    }
+}
+static void android_location_GnssLocationProvider_delete_aiding_data(JNIEnv* /* env */,
+                                                                    jobject /* obj */,
+                                                                    jint flags) {
+    if (gnssHal != nullptr) {
+        auto result = gnssHal->deleteAidingData(static_cast<IGnss::GnssAidingData>(flags));
+        if (!result.getStatus().isOk()) {
+            ALOGE("Error in deleting aiding data");
+        }
+    }
+}
+
+/*
+ * This enum is used by the read_sv_status method to combine the svid,
+ * constellation and svFlag fields.
+ */
+enum ShiftWidth: uint8_t {
+    SVID_SHIFT_WIDTH = 7,
+    CONSTELLATION_TYPE_SHIFT_WIDTH = 3
+};
+
+static jint android_location_GnssLocationProvider_read_sv_status(JNIEnv* env, jobject /* obj */,
+        jintArray svidWithFlagArray, jfloatArray cn0Array, jfloatArray elevArray,
+        jfloatArray azumArray) {
+    /*
+     * This method should only be called from within a call to reportSvStatus.
+     */
+    jint* svidWithFlags = env->GetIntArrayElements(svidWithFlagArray, 0);
+    jfloat* cn0s = env->GetFloatArrayElements(cn0Array, 0);
+    jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
+    jfloat* azim = env->GetFloatArrayElements(azumArray, 0);
+
+    /*
+     * Read GNSS SV info.
+     */
+    for (size_t i = 0; i < GnssCallback::sGnssSvListSize; ++i) {
+        const IGnssCallback::GnssSvInfo& info = GnssCallback::sGnssSvList[i];
+        svidWithFlags[i] = (info.svid << SVID_SHIFT_WIDTH) |
+            (static_cast<uint32_t>(info.constellation) << CONSTELLATION_TYPE_SHIFT_WIDTH) |
+            static_cast<uint32_t>(info.svFlag);
+        cn0s[i] = info.cN0Dbhz;
+        elev[i] = info.elevationDegrees;
+        azim[i] = info.azimuthDegrees;
+    }
+
+    env->ReleaseIntArrayElements(svidWithFlagArray, svidWithFlags, 0);
+    env->ReleaseFloatArrayElements(cn0Array, cn0s, 0);
+    env->ReleaseFloatArrayElements(elevArray, elev, 0);
+    env->ReleaseFloatArrayElements(azumArray, azim, 0);
+    return static_cast<jint>(GnssCallback::sGnssSvListSize);
+}
+
+static void android_location_GnssLocationProvider_agps_set_reference_location_cellid(
+        JNIEnv* /* env */, jobject /* obj */, jint type, jint mcc, jint mnc, jint lac, jint cid) {
+    IAGnssRil::AGnssRefLocation location;
+
+    if (agnssRilIface == nullptr) {
+        ALOGE("No AGPS RIL interface in agps_set_reference_location_cellid");
+        return;
+    }
+
+    switch (static_cast<IAGnssRil::AGnssRefLocationType>(type)) {
+        case IAGnssRil::AGnssRefLocationType::GSM_CELLID:
+        case IAGnssRil::AGnssRefLocationType::UMTS_CELLID:
+          location.type = static_cast<IAGnssRil::AGnssRefLocationType>(type);
+          location.cellID.mcc = mcc;
+          location.cellID.mnc = mnc;
+          location.cellID.lac = lac;
+          location.cellID.cid = cid;
+          break;
+        default:
+            ALOGE("Neither a GSM nor a UMTS cellid (%s:%d).", __FUNCTION__, __LINE__);
+            return;
+            break;
+    }
+
+    agnssRilIface->setRefLocation(location);
+}
+
+static void android_location_GnssLocationProvider_agps_set_id(JNIEnv *env, jobject /* obj */,
+                                                             jint type, jstring  setid_string) {
+    if (agnssRilIface == nullptr) {
+        ALOGE("no AGPS RIL interface in agps_set_id");
+        return;
+    }
+
+    const char *setid = env->GetStringUTFChars(setid_string, NULL);
+    agnssRilIface->setSetId((IAGnssRil::SetIDType)type, setid);
+    env->ReleaseStringUTFChars(setid_string, setid);
+}
+
+static jint android_location_GnssLocationProvider_read_nmea(JNIEnv* env, jobject /* obj */,
+                                            jbyteArray nmeaArray, jint buffer_size) {
+    // this should only be called from within a call to reportNmea
+    jbyte* nmea = reinterpret_cast<jbyte *>(env->GetPrimitiveArrayCritical(nmeaArray, 0));
+    int length = GnssCallback::sNmeaStringLength;
+    if (length > buffer_size)
+        length = buffer_size;
+    memcpy(nmea, GnssCallback::sNmeaString, length);
+    env->ReleasePrimitiveArrayCritical(nmeaArray, nmea, JNI_ABORT);
+    return (jint) length;
+}
+
+static void android_location_GnssLocationProvider_inject_time(JNIEnv* /* env */, jobject /* obj */,
+        jlong time, jlong timeReference, jint uncertainty) {
+    if (gnssHal != nullptr) {
+        auto result = gnssHal->injectTime(time, timeReference, uncertainty);
+        if (!result || !result.getStatus().isOk()) {
+            ALOGE("%s: Gnss injectTime() failed", __func__);
+        }
+    }
+}
+
+static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env */,
+        jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy) {
+    if (gnssHal != nullptr) {
+        auto result = gnssHal->injectLocation(latitude, longitude, accuracy);
+        if (!result || !result.getStatus().isOk()) {
+            ALOGE("%s: Gnss injectLocation() failed", __func__);
+        }
+    }
+}
+
+static jboolean android_location_GnssLocationProvider_supports_xtra(
+        JNIEnv* /* env */, jobject /* obj */) {
+    return (gnssXtraIface != nullptr) ? JNI_TRUE : JNI_FALSE;
+}
+
+static void android_location_GnssLocationProvider_inject_xtra_data(JNIEnv* env, jobject /* obj */,
+        jbyteArray data, jint length) {
+    if (gnssXtraIface == nullptr) {
+        ALOGE("XTRA Interface not supported");
+        return;
+    }
+
+    jbyte* bytes = reinterpret_cast<jbyte *>(env->GetPrimitiveArrayCritical(data, 0));
+    gnssXtraIface->injectXtraData(std::string((const char*)bytes, length));
+    env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
+}
+
+static void android_location_GnssLocationProvider_agps_data_conn_open(
+        JNIEnv* env, jobject /* obj */, jstring apn, jint apnIpType) {
+    if (agnssIface == nullptr) {
+        ALOGE("no AGPS interface in agps_data_conn_open");
+        return;
+    }
+    if (apn == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return;
+    }
+
+    const char *apnStr = env->GetStringUTFChars(apn, NULL);
+
+    auto result = agnssIface->dataConnOpen(apnStr, static_cast<IAGnss::ApnIpType>(apnIpType));
+    if ((!result) || (!result.getStatus().isOk())) {
+        ALOGE("%s: Failed to set APN and its IP type", __func__);
+    }
+    env->ReleaseStringUTFChars(apn, apnStr);
+}
+
+static void android_location_GnssLocationProvider_agps_data_conn_closed(JNIEnv* /* env */,
+                                                                       jobject /* obj */) {
+    if (agnssIface == nullptr) {
+        ALOGE("%s: AGPS interface not supported", __func__);
+        return;
+    }
+
+    auto result = agnssIface->dataConnClosed();
+    if ((!result) || (!result.getStatus().isOk())) {
+        ALOGE("%s: Failed to close AGnss data connection", __func__);
+    }
+}
+
+static void android_location_GnssLocationProvider_agps_data_conn_failed(JNIEnv* /* env */,
+                                                                       jobject /* obj */) {
+    if (agnssIface == nullptr) {
+        ALOGE("%s: AGPS interface not supported", __func__);
+        return;
+    }
+
+    auto result = agnssIface->dataConnFailed();
+    if ((!result) || (!result.getStatus().isOk())) {
+        ALOGE("%s: Failed to notify unavailability of AGnss data connection", __func__);
+    }
+}
+
+static void android_location_GnssLocationProvider_set_agps_server(JNIEnv* env, jobject /* obj */,
+        jint type, jstring hostname, jint port) {
+    if (agnssIface == nullptr) {
+        ALOGE("no AGPS interface in set_agps_server");
+        return;
+    }
+
+    const char *c_hostname = env->GetStringUTFChars(hostname, NULL);
+    auto result = agnssIface->setServer(static_cast<IAGnssCallback::AGnssType>(type),
+                                       c_hostname,
+                                       port);
+    if ((!result) || (!result.getStatus().isOk())) {
+        ALOGE("%s: Failed to set AGnss host name and port", __func__);
+    }
+
+    env->ReleaseStringUTFChars(hostname, c_hostname);
+}
+
+static void android_location_GnssLocationProvider_send_ni_response(JNIEnv* /* env */,
+      jobject /* obj */, jint notifId, jint response) {
+    if (gnssNiIface == nullptr) {
+        ALOGE("no NI interface in send_ni_response");
+        return;
+    }
+
+    gnssNiIface->respond(notifId, static_cast<IGnssNiCallback::GnssUserResponseType>(response));
+}
+
+static jstring android_location_GnssLocationProvider_get_internal_state(JNIEnv* env,
+                                                                       jobject /* obj */) {
+    jstring result = NULL;
+    /*
+     * TODO(b/33089503) : Create a jobject to represent GnssDebug.
+     */
+    if (gnssDebugIface != nullptr) {
+        IGnssDebug::DebugData data;
+        gnssDebugIface->getDebugData([&data](const IGnssDebug::DebugData& debugData) {
+            data = debugData;
+        });
+
+        std::stringstream internalState;
+        if (data.position.valid) {
+            internalState << "Gnss Location Data:: LatitudeDegrees: " << data.position.latitudeDegrees
+                          << ", LongitudeDegrees: " << data.position.longitudeDegrees
+                          << ", altitudeMeters: " << data.position.altitudeMeters
+                          << ", accuracyMeters: " << data.position.accuracyMeters
+                          << ", ageSeconds: " << data.position.ageSeconds << std::endl;
+        }
+
+        if (data.time.valid) {
+            internalState << "Gnss Time Data:: timeEstimate: " << data.time.timeEstimate
+                          << ", timeUncertaintyNs: " << data.time.timeUncertaintyNs << std::endl;
+        }
+
+        if (data.satelliteDataArray.size() != 0) {
+            internalState << "Satellite Data:: ";
+        }
+
+        for (size_t i = 0; i < data.satelliteDataArray.size(); i++) {
+            internalState << "svid: " << data.satelliteDataArray[i].svid
+                          << ", constellation: "
+                          << static_cast<uint32_t>(data.satelliteDataArray[i].constellation)
+                          << ", ephemerisType: "
+                          << static_cast<uint32_t>(data.satelliteDataArray[i].ephemerisType)
+                          << ", ephemerisAgeSeconds: "
+                          << data.satelliteDataArray[i].ephemerisAgeSeconds << std::endl;
+        }
+        result = env->NewStringUTF(internalState.str().c_str());
+    }
+    return result;
+}
+
+static void android_location_GnssLocationProvider_update_network_state(JNIEnv* env,
+                                                                       jobject /* obj */,
+                                                                       jboolean connected,
+                                                                       jint type,
+                                                                       jboolean roaming,
+                                                                       jboolean available,
+                                                                       jstring extraInfo,
+                                                                       jstring apn) {
+    if (agnssRilIface != nullptr) {
+        auto result = agnssRilIface->updateNetworkState(connected,
+                                                       static_cast<IAGnssRil::NetworkType>(type),
+                                                       roaming);
+        if ((!result) || (!result.getStatus().isOk())) {
+            ALOGE("updateNetworkState failed");
+        }
+
+        const char *c_apn = env->GetStringUTFChars(apn, NULL);
+        result = agnssRilIface->updateNetworkAvailability(available, c_apn);
+        if ((!result) || (!result.getStatus().isOk())) {
+            ALOGE("updateNetworkAvailability failed");
+        }
+
+        env->ReleaseStringUTFChars(apn, c_apn);
+    } else {
+        ALOGE("AGnssRilInterface does not exist");
+    }
+}
+
+static jboolean android_location_GnssLocationProvider_is_geofence_supported(
+        JNIEnv* /* env */, jobject /* obj */) {
+    return (gnssGeofencingIface != nullptr) ? JNI_TRUE : JNI_FALSE;
+}
+
+static jboolean android_location_GnssLocationProvider_add_geofence(JNIEnv* /* env */,
+        jobject /* obj */, jint geofenceId, jdouble latitude, jdouble longitude, jdouble radius,
+        jint last_transition, jint monitor_transition, jint notification_responsiveness,
+        jint unknown_timer) {
+    if (gnssGeofencingIface != nullptr) {
+        auto result = gnssGeofencingIface->addGeofence(
+                geofenceId, latitude, longitude, radius,
+                static_cast<IGnssGeofenceCallback::GeofenceTransition>(last_transition),
+                monitor_transition, notification_responsiveness, unknown_timer);
+        return boolToJbool(result.getStatus().isOk());
+    } else {
+        ALOGE("Geofence Interface not available");
+    }
+    return JNI_FALSE;
+}
+
+static jboolean android_location_GnssLocationProvider_remove_geofence(JNIEnv* /* env */,
+        jobject /* obj */, jint geofenceId) {
+    if (gnssGeofencingIface != nullptr) {
+        auto result = gnssGeofencingIface->removeGeofence(geofenceId);
+        return boolToJbool(result.getStatus().isOk());
+    } else {
+        ALOGE("Geofence interface not available");
+    }
+    return JNI_FALSE;
+}
+
+static jboolean android_location_GnssLocationProvider_pause_geofence(JNIEnv* /* env */,
+        jobject /* obj */, jint geofenceId) {
+    if (gnssGeofencingIface != nullptr) {
+        auto result = gnssGeofencingIface->pauseGeofence(geofenceId);
+        return boolToJbool(result.getStatus().isOk());
+    } else {
+        ALOGE("Geofence interface not available");
+    }
+    return JNI_FALSE;
+}
+
+static jboolean android_location_GnssLocationProvider_resume_geofence(JNIEnv* /* env */,
+        jobject /* obj */, jint geofenceId, jint monitor_transition) {
+    if (gnssGeofencingIface != nullptr) {
+        auto result = gnssGeofencingIface->resumeGeofence(geofenceId, monitor_transition);
+        return boolToJbool(result.getStatus().isOk());
+    } else {
+        ALOGE("Geofence interface not available");
+    }
+    return JNI_FALSE;
+}
+
 static jboolean android_location_GnssLocationProvider_is_measurement_supported(
-        JNIEnv* env,
-        jclass clazz) {
-    if (sGpsMeasurementInterface != NULL) {
+    JNIEnv* env, jclass clazz) {
+    if (gnssMeasurementIface != nullptr) {
         return JNI_TRUE;
     }
+
     return JNI_FALSE;
 }
 
 static jboolean android_location_GnssLocationProvider_start_measurement_collection(
         JNIEnv* env,
         jobject obj) {
-    if (sGpsMeasurementInterface == NULL) {
-        ALOGE("Measurement interface is not available.");
+    if (gnssMeasurementIface == nullptr) {
+        ALOGE("GNSS Measurement interface is not available.");
         return JNI_FALSE;
     }
 
-    int result = sGpsMeasurementInterface->init(&sGpsMeasurementCallbacks);
-    if (result != GPS_GEOFENCE_OPERATION_SUCCESS) {
-        ALOGE("An error has been found on GpsMeasurementInterface::init, status=%d", result);
+    sp<GnssMeasurementCallback> cbIface = new GnssMeasurementCallback();
+    IGnssMeasurement::GnssMeasurementStatus result = gnssMeasurementIface->setCallback(cbIface);
+    if (result != IGnssMeasurement::GnssMeasurementStatus::SUCCESS) {
+        ALOGE("An error has been found on GnssMeasurementInterface::init, status=%d",
+              static_cast<int32_t>(result));
         return JNI_FALSE;
+    } else {
+      ALOGD("gnss measurement infc has been enabled");
     }
 
     return JNI_TRUE;
@@ -1464,104 +1464,19 @@
 static jboolean android_location_GnssLocationProvider_stop_measurement_collection(
         JNIEnv* env,
         jobject obj) {
-    if (sGpsMeasurementInterface == NULL) {
+    if (gnssMeasurementIface == nullptr) {
         ALOGE("Measurement interface not available");
         return JNI_FALSE;
     }
 
-    sGpsMeasurementInterface->close();
-    return JNI_TRUE;
+    auto result = gnssMeasurementIface->close();
+    return boolToJbool(result.getStatus().isOk());
 }
 
-static jobject translate_gps_navigation_message(JNIEnv* env, GpsNavigationMessage* message) {
-    size_t dataLength = message->data_length;
-    uint8_t* data = message->data;
-    if (dataLength == 0 || data == NULL) {
-        ALOGE("Invalid Navigation Message found: data=%p, length=%zd", data, dataLength);
-        return NULL;
-    }
-    JavaObject object(env, "android/location/GnssNavigationMessage");
-    SET(Svid, static_cast<int32_t>(message->prn));
-    if (message->prn >=1 && message->prn <= 32) {
-        SET(ConstellationType, static_cast<int32_t>(GNSS_CONSTELLATION_GPS));
-        // Legacy driver doesn't set the higher byte to constellation type
-        // correctly. Set the higher byte to 'GPS'.
-        SET(Type, static_cast<int32_t>(message->type | 0x0100));
-    } else {
-        ALOGD("Unknown constellation type with Svid = %d.", message->prn);
-        SET(ConstellationType,
-            static_cast<int32_t>(GNSS_CONSTELLATION_UNKNOWN));
-        SET(Type, static_cast<int32_t>(GNSS_NAVIGATION_MESSAGE_TYPE_UNKNOWN));
-    }
-    SET(MessageId, static_cast<int32_t>(message->message_id));
-    SET(SubmessageId, static_cast<int32_t>(message->submessage_id));
-    object.callSetter("setData", data, dataLength);
-    SET(Status, static_cast<int32_t>(message->status));
-    return object.get();
-}
-
-static jobject translate_gnss_navigation_message(
-        JNIEnv* env, GnssNavigationMessage* message) {
-    size_t dataLength = message->data_length;
-    uint8_t* data = message->data;
-    if (dataLength == 0 || data == NULL) {
-        ALOGE("Invalid Navigation Message found: data=%p, length=%zd", data, dataLength);
-        return NULL;
-    }
-    JavaObject object(env, "android/location/GnssNavigationMessage");
-    SET(Type, static_cast<int32_t>(message->type));
-    SET(Svid, static_cast<int32_t>(message->svid));
-    SET(MessageId, static_cast<int32_t>(message->message_id));
-    SET(SubmessageId, static_cast<int32_t>(message->submessage_id));
-    object.callSetter("setData", data, dataLength);
-    SET(Status, static_cast<int32_t>(message->status));
-    return object.get();
-}
-
-static void navigation_message_callback(GpsNavigationMessage* message) {
-    if (message == NULL) {
-        ALOGE("Invalid Navigation Message provided to callback");
-        return;
-    }
-    if (message->size != sizeof(GpsNavigationMessage)) {
-        ALOGE("Invalid GpsNavigationMessage size found: %zd", message->size);
-        return;
-    }
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    jobject navigationMessage = translate_gps_navigation_message(env, message);
-    env->CallVoidMethod(mCallbacksObj,
-                        method_reportNavigationMessages,
-                        navigationMessage);
-    env->DeleteLocalRef(navigationMessage);
-}
-
-static void gnss_navigation_message_callback(GnssNavigationMessage* message) {
-    if (message == NULL) {
-        ALOGE("Invalid Navigation Message provided to callback");
-        return;
-    }
-    if (message->size != sizeof(GnssNavigationMessage)) {
-        ALOGE("Invalid GnssNavigationMessage size found: %zd", message->size);
-        return;
-    }
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    jobject navigationMessage = translate_gnss_navigation_message(env, message);
-    env->CallVoidMethod(mCallbacksObj,
-                        method_reportNavigationMessages,
-                        navigationMessage);
-    env->DeleteLocalRef(navigationMessage);
-}
-
-GpsNavigationMessageCallbacks sGpsNavigationMessageCallbacks = {
-    sizeof(GpsNavigationMessageCallbacks),
-    navigation_message_callback,
-    gnss_navigation_message_callback,
-};
-
 static jboolean android_location_GnssLocationProvider_is_navigation_message_supported(
         JNIEnv* env,
         jclass clazz) {
-    if(sGpsNavigationMessageInterface != NULL) {
+    if (gnssNavigationMessageIface != nullptr) {
         return JNI_TRUE;
     }
     return JNI_FALSE;
@@ -1570,14 +1485,18 @@
 static jboolean android_location_GnssLocationProvider_start_navigation_message_collection(
         JNIEnv* env,
         jobject obj) {
-    if (sGpsNavigationMessageInterface == NULL) {
+    if (gnssNavigationMessageIface == nullptr) {
         ALOGE("Navigation Message interface is not available.");
         return JNI_FALSE;
     }
 
-    int result = sGpsNavigationMessageInterface->init(&sGpsNavigationMessageCallbacks);
-    if (result != GPS_NAVIGATION_MESSAGE_OPERATION_SUCCESS) {
-        ALOGE("An error has been found in %s: %d", __FUNCTION__, result);
+    sp<IGnssNavigationMessageCallback> gnssNavigationMessageCbIface =
+            new GnssNavigationMessageCallback();
+    IGnssNavigationMessage::GnssNavigationMessageStatus result =
+            gnssNavigationMessageIface->setCallback(gnssNavigationMessageCbIface);
+
+    if (result != IGnssNavigationMessage::GnssNavigationMessageStatus::SUCCESS) {
+        ALOGE("An error has been found in %s: %d", __FUNCTION__, static_cast<int32_t>(result));
         return JNI_FALSE;
     }
 
@@ -1587,127 +1506,255 @@
 static jboolean android_location_GnssLocationProvider_stop_navigation_message_collection(
         JNIEnv* env,
         jobject obj) {
-    if (sGpsNavigationMessageInterface == NULL) {
+    if (gnssNavigationMessageIface == nullptr) {
         ALOGE("Navigation Message interface is not available.");
         return JNI_FALSE;
     }
 
-    sGpsNavigationMessageInterface->close();
-    return JNI_TRUE;
+    auto result = gnssNavigationMessageIface->close();
+    return boolToJbool(result.getStatus().isOk());
 }
 
-static void android_location_GnssLocationProvider_configuration_update(JNIEnv* env, jobject obj,
-        jstring config_content)
-{
-    if (!sGnssConfigurationInterface) {
-        ALOGE("no GPS configuration interface in configuraiton_update");
-        return;
+static jboolean android_location_GnssLocationProvider_set_emergency_supl_pdn(JNIEnv*,
+                                                                    jobject,
+                                                                    jint emergencySuplPdn) {
+    if (gnssConfigurationIface == nullptr) {
+        ALOGE("no GNSS configuration interface available");
+        return JNI_FALSE;
     }
-    const char *data = env->GetStringUTFChars(config_content, NULL);
-    ALOGD("GPS configuration:\n %s", data);
-    sGnssConfigurationInterface->configuration_update(
-            data, env->GetStringUTFLength(config_content));
-    env->ReleaseStringUTFChars(config_content, data);
+
+    auto result = gnssConfigurationIface->setEmergencySuplPdn(emergencySuplPdn);
+    if (result.getStatus().isOk()) {
+        return result;
+    } else {
+        return JNI_FALSE;
+    }
+}
+
+static jboolean android_location_GnssLocationProvider_set_supl_version(JNIEnv*,
+                                                                    jobject,
+                                                                    jint version) {
+    if (gnssConfigurationIface == nullptr) {
+        ALOGE("no GNSS configuration interface available");
+        return JNI_FALSE;
+    }
+    auto result = gnssConfigurationIface->setSuplVersion(version);
+    if (result.getStatus().isOk()) {
+        return result;
+    } else {
+        return JNI_FALSE;
+    }
+}
+
+static jboolean android_location_GnssLocationProvider_set_supl_es(JNIEnv*,
+                                                                    jobject,
+                                                                    jint suplEs) {
+    if (gnssConfigurationIface == nullptr) {
+        ALOGE("no GNSS configuration interface available");
+        return JNI_FALSE;
+    }
+
+    auto result = gnssConfigurationIface->setSuplEs(suplEs);
+    if (result.getStatus().isOk()) {
+        return result;
+    } else {
+        return JNI_FALSE;
+    }
+}
+
+static jboolean android_location_GnssLocationProvider_set_supl_mode(JNIEnv*,
+                                                                    jobject,
+                                                                    jint mode) {
+    if (gnssConfigurationIface == nullptr) {
+        ALOGE("no GNSS configuration interface available");
+        return JNI_FALSE;
+    }
+
+    auto result = gnssConfigurationIface->setSuplMode(mode);
+    if (result.getStatus().isOk()) {
+        return result;
+    } else {
+        return JNI_FALSE;
+    }
+}
+
+static jboolean android_location_GnssLocationProvider_set_gps_lock(JNIEnv*,
+                                                                   jobject,
+                                                                   jint gpsLock) {
+    if (gnssConfigurationIface == nullptr) {
+        ALOGE("no GNSS configuration interface available");
+        return JNI_FALSE;
+    }
+
+    auto result = gnssConfigurationIface->setGpsLock(gpsLock);
+    if (result.getStatus().isOk()) {
+        return result;
+    } else {
+        return JNI_FALSE;
+    }
+}
+
+static jboolean android_location_GnssLocationProvider_set_lpp_profile(JNIEnv*,
+                                                                   jobject,
+                                                                   jint lppProfile) {
+    if (gnssConfigurationIface == nullptr) {
+        ALOGE("no GNSS configuration interface available");
+        return JNI_FALSE;
+    }
+
+    auto result = gnssConfigurationIface->setLppProfile(lppProfile);
+
+    if (result.getStatus().isOk()) {
+        return result;
+    } else {
+        return JNI_FALSE;
+    }
+}
+
+static jboolean android_location_GnssLocationProvider_set_gnss_pos_protocol_select(JNIEnv*,
+                                                                   jobject,
+                                                                   jint gnssPosProtocol) {
+    if (gnssConfigurationIface == nullptr) {
+        ALOGE("no GNSS configuration interface available");
+        return JNI_FALSE;
+    }
+
+    auto result = gnssConfigurationIface->setGlonassPositioningProtocol(gnssPosProtocol);
+    if (result.getStatus().isOk()) {
+        return result;
+    } else {
+        return JNI_FALSE;
+    }
 }
 
 static const JNINativeMethod sMethods[] = {
      /* name, signature, funcPtr */
-    {"class_init_native", "()V", (void *)android_location_GnssLocationProvider_class_init_native},
-    {"native_is_supported", "()Z", (void*)android_location_GnssLocationProvider_is_supported},
+    {"class_init_native", "()V", reinterpret_cast<void *>(
+            android_location_GnssLocationProvider_class_init_native)},
+    {"native_is_supported", "()Z", reinterpret_cast<void *>(
+            android_location_GnssLocationProvider_is_supported)},
     {"native_is_agps_ril_supported", "()Z",
-            (void*)android_location_GnssLocationProvider_is_agps_ril_supported},
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_is_agps_ril_supported)},
     {"native_is_gnss_configuration_supported", "()Z",
-            (void*)android_location_gpsLocationProvider_is_gnss_configuration_supported},
-    {"native_init", "()Z", (void*)android_location_GnssLocationProvider_init},
-    {"native_cleanup", "()V", (void*)android_location_GnssLocationProvider_cleanup},
+            reinterpret_cast<void *>(
+                    android_location_gpsLocationProvider_is_gnss_configuration_supported)},
+    {"native_init", "()Z", reinterpret_cast<void *>(android_location_GnssLocationProvider_init)},
+    {"native_cleanup", "()V", reinterpret_cast<void *>(
+            android_location_GnssLocationProvider_cleanup)},
     {"native_set_position_mode",
             "(IIIII)Z",
-            (void*)android_location_GnssLocationProvider_set_position_mode},
-    {"native_start", "()Z", (void*)android_location_GnssLocationProvider_start},
-    {"native_stop", "()Z", (void*)android_location_GnssLocationProvider_stop},
+            reinterpret_cast<void*>(android_location_GnssLocationProvider_set_position_mode)},
+    {"native_start", "()Z", reinterpret_cast<void*>(android_location_GnssLocationProvider_start)},
+    {"native_stop", "()Z", reinterpret_cast<void*>(android_location_GnssLocationProvider_stop)},
     {"native_delete_aiding_data",
             "(I)V",
-            (void*)android_location_GnssLocationProvider_delete_aiding_data},
+            reinterpret_cast<void*>(android_location_GnssLocationProvider_delete_aiding_data)},
     {"native_read_sv_status",
             "([I[F[F[F)I",
-            (void*)android_location_GnssLocationProvider_read_sv_status},
-    {"native_read_nmea", "([BI)I", (void*)android_location_GnssLocationProvider_read_nmea},
-    {"native_inject_time", "(JJI)V", (void*)android_location_GnssLocationProvider_inject_time},
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_read_sv_status)},
+    {"native_read_nmea", "([BI)I", reinterpret_cast<void *>(
+            android_location_GnssLocationProvider_read_nmea)},
+    {"native_inject_time", "(JJI)V", reinterpret_cast<void *>(
+            android_location_GnssLocationProvider_inject_time)},
     {"native_inject_location",
             "(DDF)V",
-            (void*)android_location_GnssLocationProvider_inject_location},
-    {"native_supports_xtra", "()Z", (void*)android_location_GnssLocationProvider_supports_xtra},
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_inject_location)},
+    {"native_supports_xtra", "()Z", reinterpret_cast<void *>(
+            android_location_GnssLocationProvider_supports_xtra)},
     {"native_inject_xtra_data",
             "([BI)V",
-            (void*)android_location_GnssLocationProvider_inject_xtra_data},
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_inject_xtra_data)},
     {"native_agps_data_conn_open",
             "(Ljava/lang/String;I)V",
-            (void*)android_location_GnssLocationProvider_agps_data_conn_open},
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_agps_data_conn_open)},
     {"native_agps_data_conn_closed",
             "()V",
-            (void*)android_location_GnssLocationProvider_agps_data_conn_closed},
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_agps_data_conn_closed)},
     {"native_agps_data_conn_failed",
             "()V",
-            (void*)android_location_GnssLocationProvider_agps_data_conn_failed},
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_agps_data_conn_failed)},
     {"native_agps_set_id",
             "(ILjava/lang/String;)V",
-            (void*)android_location_GnssLocationProvider_agps_set_id},
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_agps_set_id)},
     {"native_agps_set_ref_location_cellid",
             "(IIIII)V",
-            (void*)android_location_GnssLocationProvider_agps_set_reference_location_cellid},
+            reinterpret_cast<void *>(
+                    android_location_GnssLocationProvider_agps_set_reference_location_cellid)},
     {"native_set_agps_server",
             "(ILjava/lang/String;I)V",
-            (void*)android_location_GnssLocationProvider_set_agps_server},
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_set_agps_server)},
     {"native_send_ni_response",
             "(II)V",
-            (void*)android_location_GnssLocationProvider_send_ni_response},
-    {"native_agps_ni_message",
-            "([BI)V",
-            (void *)android_location_GnssLocationProvider_agps_send_ni_message},
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_send_ni_response)},
     {"native_get_internal_state",
             "()Ljava/lang/String;",
-            (void*)android_location_GnssLocationProvider_get_internal_state},
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_get_internal_state)},
     {"native_update_network_state",
             "(ZIZZLjava/lang/String;Ljava/lang/String;)V",
-            (void*)android_location_GnssLocationProvider_update_network_state },
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_update_network_state)},
     {"native_is_geofence_supported",
             "()Z",
-            (void*) android_location_GnssLocationProvider_is_geofence_supported},
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_is_geofence_supported)},
     {"native_add_geofence",
             "(IDDDIIII)Z",
-            (void *)android_location_GnssLocationProvider_add_geofence},
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_add_geofence)},
     {"native_remove_geofence",
             "(I)Z",
-            (void *)android_location_GnssLocationProvider_remove_geofence},
-    {"native_pause_geofence", "(I)Z", (void *)android_location_GnssLocationProvider_pause_geofence},
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_remove_geofence)},
+    {"native_pause_geofence", "(I)Z", reinterpret_cast<void *>(
+            android_location_GnssLocationProvider_pause_geofence)},
     {"native_resume_geofence",
             "(II)Z",
-            (void *)android_location_GnssLocationProvider_resume_geofence},
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_resume_geofence)},
     {"native_is_measurement_supported",
             "()Z",
-            (void*) android_location_GnssLocationProvider_is_measurement_supported},
+            reinterpret_cast<void *>(
+                    android_location_GnssLocationProvider_is_measurement_supported)},
     {"native_start_measurement_collection",
             "()Z",
-            (void*) android_location_GnssLocationProvider_start_measurement_collection},
+            reinterpret_cast<void *>(
+                    android_location_GnssLocationProvider_start_measurement_collection)},
     {"native_stop_measurement_collection",
             "()Z",
-            (void*) android_location_GnssLocationProvider_stop_measurement_collection},
+            reinterpret_cast<void *>(
+                    android_location_GnssLocationProvider_stop_measurement_collection)},
     {"native_is_navigation_message_supported",
             "()Z",
-            (void*) android_location_GnssLocationProvider_is_navigation_message_supported},
+            reinterpret_cast<void *>(
+                    android_location_GnssLocationProvider_is_navigation_message_supported)},
     {"native_start_navigation_message_collection",
             "()Z",
-            (void*) android_location_GnssLocationProvider_start_navigation_message_collection},
+            reinterpret_cast<void *>(
+                    android_location_GnssLocationProvider_start_navigation_message_collection)},
     {"native_stop_navigation_message_collection",
             "()Z",
-            (void*) android_location_GnssLocationProvider_stop_navigation_message_collection},
-    {"native_configuration_update",
-            "(Ljava/lang/String;)V",
-            (void*)android_location_GnssLocationProvider_configuration_update},
+            reinterpret_cast<void *>(
+                    android_location_GnssLocationProvider_stop_navigation_message_collection)},
+    {"native_set_supl_es",
+            "(I)Z",
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_set_supl_es)},
+    {"native_set_supl_version",
+            "(I)Z",
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_set_supl_version)},
+    {"native_set_supl_mode",
+            "(I)Z",
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_set_supl_mode)},
+    {"native_set_lpp_profile",
+            "(I)Z",
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_set_lpp_profile)},
+    {"native_set_gnss_pos_protocol_select",
+            "(I)Z",
+            reinterpret_cast<void *>(
+                    android_location_GnssLocationProvider_set_gnss_pos_protocol_select)},
+    {"native_set_gps_lock",
+            "(I)Z",
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_set_gps_lock)},
+    {"native_set_emergency_supl_pdn",
+            "(I)Z",
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_set_emergency_supl_pdn)},
 };
 
-int register_android_server_location_GnssLocationProvider(JNIEnv* env)
-{
+int register_android_server_location_GnssLocationProvider(JNIEnv* env) {
     return jniRegisterNativeMethods(
             env,
             "com/android/server/location/GnssLocationProvider",
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 034b0cd..a2af40c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -20,7 +20,7 @@
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
 import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
 import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
-import static android.content.pm.PackageManager.GET_UNINSTALLED_PACKAGES;
+import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
 
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
@@ -5979,6 +5979,12 @@
         }
     }
 
+    @Override
+    public boolean hasDeviceOwner() {
+        enforceDeviceOwnerOrManageUsers();
+        return mOwners.hasDeviceOwner();
+    }
+
     boolean isDeviceOwner(ActiveAdmin admin) {
         return isDeviceOwner(admin.info.getComponent(), admin.getUserHandle().getIdentifier());
     }
@@ -7026,7 +7032,8 @@
                 boolean systemService = false;
                 try {
                     ApplicationInfo applicationInfo = mIPackageManager.getApplicationInfo(
-                            enabledPackage, PackageManager.GET_UNINSTALLED_PACKAGES, userIdToCheck);
+                            enabledPackage, PackageManager.MATCH_UNINSTALLED_PACKAGES,
+                            userIdToCheck);
                     systemService = (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
                 } catch (RemoteException e) {
                     Log.i(LOG_TAG, "Can't talk to package managed", e);
@@ -7781,7 +7788,7 @@
 
     private boolean isSystemApp(IPackageManager pm, String packageName, int userId)
             throws RemoteException {
-        ApplicationInfo appInfo = pm.getApplicationInfo(packageName, GET_UNINSTALLED_PACKAGES,
+        ApplicationInfo appInfo = pm.getApplicationInfo(packageName, MATCH_UNINSTALLED_PACKAGES,
                 userId);
         if (appInfo == null) {
             throw new IllegalArgumentException("The application " + packageName +
@@ -9120,7 +9127,7 @@
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = mInjector.userHandleGetCallingUserId();
-        enforceManagedProfile(userHandle, "set organization name");
+
         synchronized (this) {
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -9147,6 +9154,18 @@
     }
 
     @Override
+    public CharSequence getDeviceOwnerOrganizationName() {
+        if (!mHasFeature) {
+            return null;
+        }
+        enforceDeviceOwnerOrManageUsers();
+        synchronized(this) {
+            final ActiveAdmin deviceOwnerAdmin = getDeviceOwnerAdminLocked();
+            return deviceOwnerAdmin == null ? null : deviceOwnerAdmin.organizationName;
+        }
+    }
+
+    @Override
     public CharSequence getOrganizationNameForUser(int userHandle) {
         if (!mHasFeature) {
             return null;
@@ -9590,6 +9609,10 @@
         Preconditions.checkNotNull(admin);
         Preconditions.checkNotNull(caller);
         Preconditions.checkNotNull(serviceIntent);
+        Preconditions.checkArgument(
+                serviceIntent.getComponent() != null || serviceIntent.getPackage() != null,
+                "Service intent must be explicit (with a package name or component): "
+                        + serviceIntent);
         Preconditions.checkNotNull(connection);
         Preconditions.checkArgument(mInjector.userHandleGetCallingUserId() != targetUserId,
                 "target user id must be different from the calling user id");
@@ -9610,9 +9633,8 @@
                     createCrossUserServiceIntent(serviceIntent, targetPackage, targetUserId);
             if (sanitizedIntent == null) {
                 // Fail, cannot lookup the target service.
-                throw new SecurityException("Invalid intent or failed to look up the service");
+                return false;
             }
-
             // Ask ActivityManager to bind it. Notice that we are binding the service with the
             // caller app instead of DevicePolicyManagerService.
             return mInjector.getIActivityManager().bindService(
@@ -9654,8 +9676,7 @@
             final long callingIdentity = mInjector.binderClearCallingIdentity();
             try {
                 String callingOwnerPackage = callingOwner.info.getComponent().getPackageName();
-                for (int userId : mUserManager.getProfileIds(
-                        callingUserId, /* enabledOnly= */ false)) {
+                for (int userId : mUserManager.getProfileIdsWithDisabled(callingUserId)) {
                     if (userId == callingUserId) {
                         continue;
                     }
@@ -9868,35 +9889,30 @@
     }
 
     /**
-     * @param rawIntent Original service intent specified by caller.
-     * @param expectedPackageName The expected package name in the incoming intent.
-     * @return Intent that have component explicitly set. {@code null} if the incoming intent
-     *         or target service is invalid.
+     * @param rawIntent Original service intent specified by caller. It must be explicit.
+     * @param expectedPackageName The expected package name of the resolved service.
+     * @return Intent that have component explicitly set. {@code null} if no service is resolved
+     *     with the given intent.
+     * @throws SecurityException if the intent is resolved to an invalid service.
      */
     private Intent createCrossUserServiceIntent(
             @NonNull Intent rawIntent, @NonNull String expectedPackageName,
-            @UserIdInt int targetUserId) throws RemoteException {
-        if (rawIntent.getComponent() == null && rawIntent.getPackage() == null) {
-            Log.e(LOG_TAG, "Service intent must be explicit (with a package name or component): "
-                    + rawIntent);
-            return null;
-        }
+            @UserIdInt int targetUserId) throws RemoteException, SecurityException {
         ResolveInfo info = mIPackageManager.resolveService(
                 rawIntent,
                 rawIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
                 0,  // flags
                 targetUserId);
         if (info == null || info.serviceInfo == null) {
-            Log.e(LOG_TAG, "Fail to look up the service: " + rawIntent);
+            Log.e(LOG_TAG, "Fail to look up the service: " + rawIntent
+                    + " or user " + targetUserId + " is not running");
             return null;
         }
         if (!expectedPackageName.equals(info.serviceInfo.packageName)) {
-            Log.e(LOG_TAG, "Only allow to bind service in " + expectedPackageName);
-            return null;
+            throw new SecurityException("Only allow to bind service in " + expectedPackageName);
         }
         if (info.serviceInfo.exported) {
-            Log.e(LOG_TAG, "The service must be unexported.");
-            return null;
+            throw new SecurityException("The service must be unexported");
         }
         // It is the system server to bind the service, it would be extremely dangerous if it
         // can be exploited to bind any service. Set the component explicitly to make sure we
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index a8356dc..83001df 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -194,8 +194,10 @@
             { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
 
     private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
-    private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
+    private static final int ICMP6_ROUTER_SOLICITATION = 133;
     private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
+    private static final int ICMP6_NEIGHBOR_SOLICITATION = 135;
+    private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
 
     // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
     private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 2;
@@ -805,6 +807,8 @@
         //   if it's multicast and we're dropping multicast:
         //     drop
         //   pass
+        // if it's ICMPv6 RS to any:
+        //   drop
         // if it's ICMPv6 NA to ff02::1:
         //   drop
 
@@ -829,10 +833,12 @@
 
         // Add unsolicited multicast neighbor announcements filter
         String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA";
-        // If not neighbor announcements, skip unsolicited multicast NA filter
         gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
+        // Drop all router solicitations (b/32833400)
+        gen.addJumpIfR0Equals(ICMP6_ROUTER_SOLICITATION, gen.DROP_LABEL);
+        // If not neighbor announcements, skip filter.
         gen.addJumpIfR0NotEquals(ICMP6_NEIGHBOR_ANNOUNCEMENT, skipUnsolicitedMulticastNALabel);
-        // If to ff02::1, drop
+        // If to ff02::1, drop.
         // TODO: Drop only if they don't contain the address of on-link neighbours.
         gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET);
         gen.addJumpIfBytesNotEqual(Register.R0, IPV6_ALL_NODES_ADDRESS,
@@ -852,6 +858,7 @@
      * <li>Pass all non-ICMPv6 IPv6 packets,
      * <li>Pass all non-IPv4 and non-IPv6 packets,
      * <li>Drop IPv6 ICMPv6 NAs to ff02::1.
+     * <li>Drop IPv6 ICMPv6 RSs.
      * <li>Let execution continue off the end of the program for IPv6 ICMPv6 packets. This allows
      *     insertion of RA filters here, or if there aren't any, just passes the packets.
      * </ul>
diff --git a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 39c5238..ad436724a 100644
--- a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -211,8 +211,9 @@
                 defaults |= Notification.DEFAULT_VIBRATE;
             } else {
                 builder.setVibrate(CUSTOM_VIBRATION);
+                channel.setVibrationPattern(CUSTOM_VIBRATION);
             }
-            channel.setVibration(true);
+            channel.enableVibration(true);
         }
         if (lights) {
             if (defaultLights) {
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
new file mode 100644
index 0000000..e4a355f
--- /dev/null
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification;
+
+import static junit.framework.Assert.fail;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.INotificationManager;
+import android.app.IOnNotificationChannelCreatedListener;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import java.util.concurrent.CountDownLatch;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NotificationManagerServiceTest {
+    private NotificationManagerService mNotificationManagerService;
+    private INotificationManager mBinderService;
+
+    @Before
+    public void setUp() throws Exception {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        mNotificationManagerService = new NotificationManagerService(context);
+
+        // MockPackageManager - default returns ApplicationInfo with matching calling UID
+        final IPackageManager mockPackageManager = mock(IPackageManager.class);
+        final ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.uid = Binder.getCallingUid();
+        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.
+        mBinderService = mNotificationManagerService.getBinderService();
+    }
+
+    @Test
+    public void testCreateNotificationChannel_SuccessCallsListener() throws Exception {
+        final NotificationChannel channel =
+                new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
+        final CountDownLatch latch = new CountDownLatch(1);
+        mBinderService.createNotificationChannel("test_pkg", channel,
+                new IOnNotificationChannelCreatedListener.Stub() {
+                    @Override public void onNotificationChannelCreated(
+                            NotificationChannel channel) {
+                        latch.countDown();
+                    }});
+        latch.await();
+    }
+
+    @Test
+    public void testCreateNotificationChannel_FailureDoesNotCallListener() throws Exception {
+        try {
+            mBinderService.createNotificationChannel("test_pkg", null,
+                    new IOnNotificationChannelCreatedListener.Stub() {
+                        @Override public void onNotificationChannelCreated(
+                                NotificationChannel channel) {
+                            fail("Listener was triggered from failure.");
+                        }});
+            fail("Exception should be thrown immediately.");
+        } catch (NullPointerException e) {
+            // pass
+        }
+    }
+}
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 b8f3832..a7d2c04 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
@@ -81,6 +81,7 @@
             300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
             300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
             300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400 };
+    private static final long[] CUSTOM_CHANNEL_VIBRATION = new long[] {300, 400, 300, 400 };
     private static final Uri CUSTOM_SOUND = Settings.System.DEFAULT_ALARM_ALERT_URI;
     private static final AudioAttributes CUSTOM_ATTRIBUTES = new AudioAttributes.Builder()
             .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
@@ -124,6 +125,7 @@
                 defaults |= Notification.DEFAULT_VIBRATE;
             } else {
                 builder.setVibrate(CUSTOM_VIBRATION);
+                channel.setVibrationPattern(CUSTOM_CHANNEL_VIBRATION);
             }
         }
         builder.setDefaults(defaults);
@@ -193,7 +195,7 @@
 
     @Test
     public void testVibration_default_preUpgradeUsesNotification() throws Exception {
-        defaultChannel.setVibration(false);
+        defaultChannel.enableVibration(false);
         // pre upgrade, default vibration.
         StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
                 false /* defaultSound */, true /* buzzy */, true /* defaultBuzz */);
@@ -204,7 +206,7 @@
 
     @Test
     public void testVibration_custom_preUpgradeUsesNotification() throws Exception {
-        defaultChannel.setVibration(false);
+        defaultChannel.enableVibration(false);
         // pre upgrade, custom vibration.
         StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
                 false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */);
@@ -215,7 +217,7 @@
 
     @Test
     public void testVibration_custom_userLocked_preUpgrade() throws Exception {
-        defaultChannel.setVibration(true);
+        defaultChannel.enableVibration(true);
         defaultChannel.lockFields(NotificationChannel.USER_LOCKED_VIBRATION);
         // pre upgrade, custom vibration.
         StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
@@ -227,13 +229,13 @@
 
     @Test
     public void testVibration_custom_upgradeUsesChannel() throws Exception {
-        channel.setVibration(true);
+        channel.enableVibration(true);
         // post upgrade, custom vibration.
         StatusBarNotification sbn = getNotification(false /*preO */, false /* noisy */,
                 false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */);
 
         NotificationRecord record = new NotificationRecord(mMockContext, sbn);
-        assertTrue(!Objects.equals(CUSTOM_VIBRATION, record.getVibration()));
+        assertEquals(CUSTOM_CHANNEL_VIBRATION, record.getVibration());
     }
 
     @Test
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 3df0d66..16d0a75 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -15,6 +15,8 @@
  */
 package com.android.server.notification;
 
+import static junit.framework.Assert.fail;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -46,6 +48,7 @@
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.util.ArrayList;
+import java.util.Arrays;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -168,6 +171,18 @@
         return baos;
     }
 
+    private void compareChannels(NotificationChannel expected, NotificationChannel actual) {
+        assertEquals(expected.getId(), actual.getId());
+        assertEquals(expected.getName(), actual.getName());
+        assertEquals(expected.shouldVibrate(), actual.shouldVibrate());
+        assertEquals(expected.shouldShowLights(), actual.shouldShowLights());
+        assertEquals(expected.getImportance(), actual.getImportance());
+        assertEquals(expected.getLockscreenVisibility(), actual.getLockscreenVisibility());
+        assertEquals(expected.getSound(), actual.getSound());
+        assertEquals(expected.canBypassDnd(), actual.canBypassDnd());
+        assertTrue(Arrays.equals(expected.getVibrationPattern(), actual.getVibrationPattern()));
+    }
+
     @Test
     public void testFindAfterRankingWithASplitGroup() throws Exception {
         ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(3);
@@ -228,6 +243,8 @@
         channel2.setLights(true);
         channel2.setBypassDnd(true);
         channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
+        channel2.enableVibration(true);
+        channel2.setVibrationPattern(new long[] {100, 67, 145, 156});
 
         mHelper.createNotificationChannel(pkg, uid, channel1);
         mHelper.createNotificationChannel(pkg, uid, channel2);
@@ -246,7 +263,7 @@
         mHelper.readXml(parser, false);
 
         assertEquals(channel1, mHelper.getNotificationChannel(pkg, uid, channel1.getId()));
-        assertEquals(channel2, mHelper.getNotificationChannel(pkg, uid, channel2.getId()));
+        compareChannels(channel2, mHelper.getNotificationChannel(pkg, uid, channel2.getId()));
         assertNotNull(
                 mHelper.getNotificationChannel(pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID));
     }
@@ -333,6 +350,19 @@
     }
 
     @Test
+    public void testCreateChannel_blocked() throws Exception {
+        mHelper.setImportance(pkg, uid, NotificationManager.IMPORTANCE_NONE);
+
+        try {
+            mHelper.createNotificationChannel(pkg, uid,
+                    new NotificationChannel(pkg, "", NotificationManager.IMPORTANCE_LOW));
+            fail("Channel creation should fail");
+        } catch (IllegalArgumentException e) {
+            // pass
+        }
+    }
+
+    @Test
     public void testUpdate_userLockedImportance() throws Exception {
         // all fields locked by user
         final NotificationChannel channel =
@@ -385,7 +415,8 @@
         // same id, try to update
         final NotificationChannel channel2 =
             new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
-        channel2.setVibration(true);
+        channel2.enableVibration(true);
+        channel2.setVibrationPattern(new long[] {100});
 
         mHelper.updateNotificationChannelFromRanker(pkg, uid, channel2);
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/GestureDescriptionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/GestureDescriptionTest.java
new file mode 100644
index 0000000..b876a5f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/GestureDescriptionTest.java
@@ -0,0 +1,420 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.accessibility;
+
+import static android.accessibilityservice.GestureDescription.StrokeDescription.INVALID_STROKE_ID;
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.CoreMatchers.everyItem;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import android.accessibilityservice.GestureDescription;
+import android.accessibilityservice.GestureDescription.GestureStep;
+import android.accessibilityservice.GestureDescription.MotionEventGenerator;
+import android.accessibilityservice.GestureDescription.StrokeDescription;
+import android.graphics.Path;
+import android.graphics.PointF;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+import org.junit.Test;
+
+import java.util.List;
+
+import static junit.framework.TestCase.assertEquals;
+
+/**
+ * Tests for GestureDescription
+ */
+public class GestureDescriptionTest {
+    @Test
+    public void testGestureShorterThanSampleRate_producesStartAndEnd() {
+        PointF click = new PointF(10, 20);
+        Path clickPath = new Path();
+        clickPath.moveTo(click.x, click.y);
+        StrokeDescription clickStroke = new StrokeDescription(clickPath, 0, 10);
+        GestureDescription.Builder clickBuilder = new GestureDescription.Builder();
+        clickBuilder.addStroke(clickStroke);
+        GestureDescription clickGesture = clickBuilder.build();
+
+        List<GestureStep> clickGestureSteps = MotionEventGenerator
+                .getGestureStepsFromGestureDescription(clickGesture, 100);
+
+        assertEquals(2, clickGestureSteps.size());
+        assertThat(clickGestureSteps.get(0), allOf(numTouchPointsIs(1), numStartsOfStroke(1),
+                numEndsOfStroke(0), hasPoint(click)));
+        assertThat(clickGestureSteps.get(1), allOf(numTouchPointsIs(1), numStartsOfStroke(0),
+                numEndsOfStroke(1), hasPoint(click)));
+    }
+
+    @Test
+    public void testSwipe_shouldContainEvenlySpacedPoints() {
+        int samplePeriod = 10;
+        int numSamples = 5;
+        float stepX = 2;
+        float stepY = 3;
+        PointF start = new PointF(10, 20);
+        PointF end = new PointF(10 + numSamples * stepX, 20 + numSamples * stepY);
+
+        GestureDescription swipe =
+                createSwipe(start.x, start.y, end.x, end.y, numSamples * samplePeriod);
+        List<GestureStep> swipeGestureSteps = MotionEventGenerator
+                .getGestureStepsFromGestureDescription(swipe, samplePeriod);
+        assertEquals(numSamples + 1, swipeGestureSteps.size());
+
+        assertThat(swipeGestureSteps.get(0), allOf(numTouchPointsIs(1), numStartsOfStroke(1),
+                numEndsOfStroke(0), hasPoint(start)));
+        assertThat(swipeGestureSteps.get(numSamples), allOf(numTouchPointsIs(1),
+                numStartsOfStroke(0), numEndsOfStroke(1), hasPoint(end)));
+
+        for (int i = 1; i < numSamples; ++i) {
+            PointF interpPoint = new PointF(start.x + stepX * i, start.y + stepY * i);
+            assertThat(swipeGestureSteps.get(i), allOf(numTouchPointsIs(1),
+                    numStartsOfStroke(0), numEndsOfStroke(0), hasPoint(interpPoint)));
+        }
+    }
+
+    @Test
+    public void testSwipeWithNonIntegerValues_shouldRound() {
+        int strokeTime = 10;
+
+        GestureDescription swipe = createSwipe(10.1f, 20.6f, 11.9f, 22.1f, strokeTime);
+        List<GestureStep> swipeGestureSteps = MotionEventGenerator
+                .getGestureStepsFromGestureDescription(swipe, strokeTime);
+        assertEquals(2, swipeGestureSteps.size());
+        assertThat(swipeGestureSteps.get(0), hasPoint(new PointF(10, 21)));
+        assertThat(swipeGestureSteps.get(1), hasPoint(new PointF(12, 22)));
+    }
+
+    @Test
+    public void testPathsWithOverlappingTiming_produceCorrectSteps() {
+        // There are 4 paths
+        // 0: an L-shaped path that starts first
+        // 1: a swipe that starts in the middle of the L-shaped path and ends when the L ends
+        // 2: a swipe that starts at the same time as #1 but extends past the end of the L
+        // 3: a swipe that starts when #3 ends
+        PointF path0Start = new PointF(100, 150);
+        PointF path0Turn = new PointF(100, 200);
+        PointF path0End = new PointF(250, 200);
+        int path0StartTime = 0;
+        int path0EndTime = 100;
+        int path0Duration = path0EndTime - path0StartTime;
+        Path path0 = new Path();
+        path0.moveTo(path0Start.x, path0Start.y);
+        path0.lineTo(path0Turn.x, path0Turn.y);
+        path0.lineTo(path0End.x, path0End.y);
+        StrokeDescription path0Stroke = new StrokeDescription(path0, path0StartTime, path0Duration);
+
+        PointF path1Start = new PointF(300, 350);
+        PointF path1End = new PointF(300, 400);
+        int path1StartTime = 50;
+        int path1EndTime = path0EndTime;
+        StrokeDescription path1Stroke = createSwipeStroke(
+                path1Start.x, path1Start.y, path1End.x, path1End.y, path1StartTime, path1EndTime);
+
+        PointF path2Start = new PointF(400, 450);
+        PointF path2End = new PointF(400, 500);
+        int path2StartTime = 50;
+        int path2EndTime = 150;
+        StrokeDescription path2Stroke = createSwipeStroke(
+                path2Start.x, path2Start.y, path2End.x, path2End.y, path2StartTime, path2EndTime);
+
+        PointF path3Start = new PointF(500, 550);
+        PointF path3End = new PointF(500, 600);
+        int path3StartTime = path2EndTime;
+        int path3EndTime = 200;
+        StrokeDescription path3Stroke = createSwipeStroke(
+                path3Start.x, path3Start.y, path3End.x, path3End.y, path3StartTime, path3EndTime);
+
+        int deltaT = 12; // Force samples to happen on extra boundaries
+        GestureDescription.Builder builder = new GestureDescription.Builder();
+        builder.addStroke(path0Stroke);
+        builder.addStroke(path1Stroke);
+        builder.addStroke(path2Stroke);
+        builder.addStroke(path3Stroke);
+        List<GestureStep> steps = MotionEventGenerator
+                .getGestureStepsFromGestureDescription(builder.build(), deltaT);
+
+        long start = 0;
+        assertThat(steps.get(0), allOf(numStartsOfStroke(1), numEndsOfStroke(0), isAtTime(start),
+                numTouchPointsIs(1), hasPoint(path0Start)));
+        assertThat(steps.get(1), allOf(numTouchPointsIs(1), noStartsOrEnds(),
+                isAtTime(start + deltaT)));
+        assertThat(steps.get(2), allOf(numTouchPointsIs(1), isAtTime(start + deltaT * 2)));
+        assertThat(steps.get(3), allOf(numTouchPointsIs(1), isAtTime(start + deltaT * 3)));
+        assertThat(steps.get(4), allOf(numTouchPointsIs(1), isAtTime(start + deltaT * 4)));
+
+        assertThat(steps.get(5), allOf(numTouchPointsIs(3), numStartsOfStroke(2),
+                numEndsOfStroke(0), isAtTime(path1StartTime), hasPoint(path1Start),
+                hasPoint(path2Start)));
+
+        start = path1StartTime;
+        assertThat(steps.get(6), allOf(numTouchPointsIs(3), isAtTime(start + deltaT * 1)));
+        assertThat(steps.get(7), allOf(noStartsOrEnds(), isAtTime(start + deltaT * 2)));
+        assertThat(steps.get(8), allOf(numTouchPointsIs(3), isAtTime(start + deltaT * 3)));
+        assertThat(steps.get(9), allOf(noStartsOrEnds(), isAtTime(start + deltaT * 4)));
+
+        assertThat(steps.get(10), allOf(numTouchPointsIs(3), numStartsOfStroke(0),
+                numEndsOfStroke(2), isAtTime(path0EndTime), hasPoint(path0End),
+                hasPoint(path1End)));
+
+        start = path0EndTime;
+        assertThat(steps.get(11), allOf(numTouchPointsIs(1), isAtTime(start + deltaT * 1)));
+        assertThat(steps.get(12), allOf(noStartsOrEnds(), isAtTime(start + deltaT * 2)));
+        assertThat(steps.get(13), allOf(numTouchPointsIs(1), isAtTime(start + deltaT * 3)));
+        assertThat(steps.get(14), allOf(noStartsOrEnds(), isAtTime(start + deltaT * 4)));
+
+        assertThat(steps.get(15), allOf(numTouchPointsIs(2), numStartsOfStroke(1),
+                numEndsOfStroke(1), isAtTime(path2EndTime), hasPoint(path2End),
+                hasPoint(path3Start)));
+
+        start = path2EndTime;
+        assertThat(steps.get(16), allOf(numTouchPointsIs(1), isAtTime(start + deltaT * 1)));
+        assertThat(steps.get(17), allOf(noStartsOrEnds(), isAtTime(start + deltaT * 2)));
+        assertThat(steps.get(18), allOf(numTouchPointsIs(1), isAtTime(start + deltaT * 3)));
+        assertThat(steps.get(19), allOf(noStartsOrEnds(), isAtTime(start + deltaT * 4)));
+
+        assertThat(steps.get(20), allOf(numTouchPointsIs(1), numStartsOfStroke(0),
+                numEndsOfStroke(1), isAtTime(path3EndTime), hasPoint(path3End)));
+    }
+
+    @Test
+    public void testMaxTouchpoints_shouldHaveValidCoords() {
+        GestureDescription.Builder maxPointBuilder = new GestureDescription.Builder();
+        PointF baseStartPoint = new PointF(100, 100);
+        PointF baseEndPoint = new PointF(100, 200);
+        int xStep = 10;
+        int samplePeriod = 15;
+        int numSamples = 2;
+        int numPoints = GestureDescription.getMaxStrokeCount();
+        for (int i = 0; i < numPoints; i++) {
+            Path path = new Path();
+            path.moveTo(baseStartPoint.x + i * xStep, baseStartPoint.y);
+            path.lineTo(baseEndPoint.x + i * xStep, baseEndPoint.y);
+            maxPointBuilder.addStroke(new StrokeDescription(path, 0, samplePeriod * numSamples));
+        }
+
+        List<GestureStep> steps = MotionEventGenerator
+                .getGestureStepsFromGestureDescription(maxPointBuilder.build(), samplePeriod);
+        assertEquals(3, steps.size());
+
+        assertThat(steps.get(0), allOf(numTouchPointsIs(numPoints), numStartsOfStroke(numPoints),
+                numEndsOfStroke(0), isAtTime(0)));
+        assertThat(steps.get(1), allOf(numTouchPointsIs(numPoints), numStartsOfStroke(0),
+                numEndsOfStroke(0), isAtTime(samplePeriod)));
+        assertThat(steps.get(2), allOf(numTouchPointsIs(numPoints), numStartsOfStroke(0),
+                numEndsOfStroke(numPoints), isAtTime(samplePeriod * 2)));
+
+        PointF baseMidPoint = new PointF((baseStartPoint.x + baseEndPoint.x) / 2,
+                (baseStartPoint.y + baseEndPoint.y) / 2);
+        for (int i = 0; i < numPoints; i++) {
+            assertThat(steps.get(0),
+                    hasPoint(new PointF(baseStartPoint.x + i * xStep, baseStartPoint.y)));
+            assertThat(steps.get(1),
+                    hasPoint(new PointF(baseMidPoint.x + i * xStep, baseMidPoint.y)));
+            assertThat(steps.get(2),
+                    hasPoint(new PointF(baseEndPoint.x + i * xStep, baseEndPoint.y)));
+        }
+    }
+
+    @Test
+    public void testGetGestureSteps_touchPointsHaveStrokeId() {
+        StrokeDescription swipeStroke = createSwipeStroke(10, 20, 30, 40, 0, 100);
+        GestureDescription swipe = new GestureDescription.Builder().addStroke(swipeStroke).build();
+        List<GestureStep> swipeGestureSteps = MotionEventGenerator
+                .getGestureStepsFromGestureDescription(swipe, 10);
+
+        assertThat(swipeGestureSteps, everyItem(hasStrokeId(swipeStroke.getId())));
+    }
+
+    @Test
+    public void testGetGestureSteps_continuedStroke_hasNoEndPoint() {
+        Path swipePath = new Path();
+        swipePath.moveTo(10, 20);
+        swipePath.lineTo(30, 40);
+        StrokeDescription stroke1 =
+                new StrokeDescription(swipePath, 0, 100, 0, true);
+        GestureDescription gesture = new GestureDescription.Builder().addStroke(stroke1).build();
+        List<GestureStep> steps = MotionEventGenerator
+                .getGestureStepsFromGestureDescription(gesture, 10);
+
+        assertThat(steps, everyItem(numEndsOfStroke(0)));
+    }
+
+    @Test
+    public void testGetGestureSteps_continuingStroke_hasNoStartPointAndHasContinuedId() {
+        Path swipePath = new Path();
+        swipePath.moveTo(10, 20);
+        swipePath.lineTo(30, 40);
+        StrokeDescription stroke1 =
+                new StrokeDescription(swipePath, 0, 100, INVALID_STROKE_ID, true);
+        StrokeDescription stroke2 =
+                new StrokeDescription(swipePath, 0, 100, stroke1.getId(), false);
+        GestureDescription gesture = new GestureDescription.Builder().addStroke(stroke2).build();
+        List<GestureStep> steps = MotionEventGenerator
+                .getGestureStepsFromGestureDescription(gesture, 10);
+
+        assertThat(steps, everyItem(
+                allOf(continuesStrokeId(stroke1.getId()), numStartsOfStroke(0))));
+    }
+
+    private GestureDescription createSwipe(
+            float startX, float startY, float endX, float endY, long duration) {
+        GestureDescription.Builder swipeBuilder = new GestureDescription.Builder();
+        swipeBuilder.addStroke(createSwipeStroke(startX, startY, endX, endY, 0, duration));
+        return swipeBuilder.build();
+    }
+
+    private StrokeDescription createSwipeStroke(
+            float startX, float startY, float endX, float endY, long startTime, long endTime) {
+        Path swipePath = new Path();
+        swipePath.moveTo(startX, startY);
+        swipePath.lineTo(endX, endY);
+        StrokeDescription swipeStroke =
+                new StrokeDescription(swipePath, startTime, endTime - startTime);
+        return swipeStroke;
+    }
+
+    Matcher<GestureStep> numTouchPointsIs(final int numTouchPoints) {
+        return new TypeSafeMatcher<GestureStep>() {
+            @Override
+            protected boolean matchesSafely(GestureStep gestureStep) {
+                return gestureStep.numTouchPoints == numTouchPoints;
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("Has " + numTouchPoints + " touch point(s)");
+            }
+        };
+    }
+
+    Matcher<GestureStep> numStartsOfStroke(final int numStarts) {
+        return new TypeSafeMatcher<GestureStep>() {
+            @Override
+            protected boolean matchesSafely(GestureStep gestureStep) {
+                int numStartsFound = 0;
+                for (int i = 0; i < gestureStep.numTouchPoints; i++) {
+                    if (gestureStep.touchPoints[i].mIsStartOfPath) {
+                        numStartsFound++;
+                    }
+                }
+                return numStartsFound == numStarts;
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("Starts " + numStarts + " stroke(s)");
+            }
+        };
+    }
+
+    Matcher<GestureStep> numEndsOfStroke(final int numEnds) {
+        return new TypeSafeMatcher<GestureStep>() {
+            @Override
+            protected boolean matchesSafely(GestureStep gestureStep) {
+                int numEndsFound = 0;
+                for (int i = 0; i < gestureStep.numTouchPoints; i++) {
+                    if (gestureStep.touchPoints[i].mIsEndOfPath) {
+                        numEndsFound++;
+                    }
+                }
+                return numEndsFound == numEnds;
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("Ends " + numEnds + " stroke(s)");
+            }
+        };
+    }
+
+    Matcher<GestureStep> hasPoint(final PointF point) {
+        return new TypeSafeMatcher<GestureStep>() {
+            @Override
+            protected boolean matchesSafely(GestureStep gestureStep) {
+                for (int i = 0; i < gestureStep.numTouchPoints; i++) {
+                    if ((gestureStep.touchPoints[i].mX == point.x)
+                            && (gestureStep.touchPoints[i].mY == point.y)) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("Has at least one point at " + point);
+            }
+        };
+    }
+
+    Matcher<GestureStep> hasStrokeId(final int strokeId) {
+        return new TypeSafeMatcher<GestureStep>() {
+            @Override
+            protected boolean matchesSafely(GestureStep gestureStep) {
+                for (int i = 0; i < gestureStep.numTouchPoints; i++) {
+                    if (gestureStep.touchPoints[i].mStrokeId == strokeId) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("Has at least one point with stroke id " + strokeId);
+            }
+        };
+    }
+
+    Matcher<GestureStep> continuesStrokeId(final int strokeId) {
+        return new TypeSafeMatcher<GestureStep>() {
+            @Override
+            protected boolean matchesSafely(GestureStep gestureStep) {
+                for (int i = 0; i < gestureStep.numTouchPoints; i++) {
+                    if (gestureStep.touchPoints[i].mContinuedStrokeId == strokeId) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("Continues stroke id " + strokeId);
+            }
+        };
+    }
+
+    Matcher<GestureStep> isAtTime(final long time) {
+        return new TypeSafeMatcher<GestureStep>() {
+            @Override
+            protected boolean matchesSafely(GestureStep gestureStep) {
+                return gestureStep.timeSinceGestureStart == time;
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("Is at time " + time);
+            }
+        };
+    }
+
+    Matcher<GestureStep> noStartsOrEnds() {
+        return allOf(numStartsOfStroke(0), numEndsOfStroke(0));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
index d5305d9..73344e0 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
@@ -16,9 +16,17 @@
 
 package com.android.server.accessibility;
 
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_UP;
+import static android.view.WindowManagerPolicy.FLAG_PASS_TO_USER;
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.CoreMatchers.anyOf;
+import static org.hamcrest.CoreMatchers.everyItem;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.argThat;
 import static org.mockito.Matchers.eq;
@@ -29,7 +37,10 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.verifyZeroInteractions;
 
+import android.accessibilityservice.GestureDescription.GestureStep;
+import android.accessibilityservice.GestureDescription.TouchPoint;
 import android.accessibilityservice.IAccessibilityServiceClient;
+import android.graphics.Point;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -40,11 +51,15 @@
 import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
-import android.view.WindowManagerPolicy;
+
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import android.view.accessibility.AccessibilityEvent;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -58,30 +73,59 @@
 @RunWith(AndroidJUnit4.class)
 public class MotionEventInjectorTest {
     private static final String LOG_TAG = "MotionEventInjectorTest";
-    private static final int CLICK_X = 100;
-    private static final int CLICK_Y_START = 200;
-    private static final int CLICK_Y_END = 201;
-    private static final int CLICK_DURATION = 10;
-    private static final int SEQUENCE = 50;
+    private static final Matcher<MotionEvent> IS_ACTION_DOWN =
+            new MotionEventActionMatcher(ACTION_DOWN);
+    private static final Matcher<MotionEvent> IS_ACTION_POINTER_DOWN =
+            new MotionEventActionMatcher(MotionEvent.ACTION_POINTER_DOWN);
+    private static final Matcher<MotionEvent> IS_ACTION_UP =
+            new MotionEventActionMatcher(ACTION_UP);
+    private static final Matcher<MotionEvent> IS_ACTION_POINTER_UP =
+            new MotionEventActionMatcher(MotionEvent.ACTION_POINTER_UP);
+    private static final Matcher<MotionEvent> IS_ACTION_CANCEL =
+            new MotionEventActionMatcher(MotionEvent.ACTION_CANCEL);
+    private static final Matcher<MotionEvent> IS_ACTION_MOVE =
+            new MotionEventActionMatcher(MotionEvent.ACTION_MOVE);
 
-    private static final int SECOND_CLICK_X = 1000;
-    private static final int SECOND_CLICK_Y = 2000;
-    private static final int SECOND_SEQUENCE = 51;
+    private static final Point LINE_START = new Point(100, 200);
+    private static final Point LINE_END = new Point(100, 300);
+    private static final int LINE_DURATION = 100;
+    private static final int LINE_SEQUENCE = 50;
+
+    private static final Point CLICK_POINT = new Point(1000, 2000);
+    private static final int CLICK_DURATION = 10;
+    private static final int CLICK_SEQUENCE = 51;
 
     private static final int MOTION_EVENT_SOURCE = InputDevice.SOURCE_TOUCHSCREEN;
     private static final int OTHER_EVENT_SOURCE = InputDevice.SOURCE_MOUSE;
 
+    private static final Point CONTINUED_LINE_START = new Point(500, 300);
+    private static final Point CONTINUED_LINE_MID1 = new Point(500, 400);
+    private static final Point CONTINUED_LINE_MID2 = new Point(600, 300);
+    private static final Point CONTINUED_LINE_END = new Point(600, 400);
+    private static final int CONTINUED_LINE_STROKE_ID_1 = 100;
+    private static final int CONTINUED_LINE_STROKE_ID_2 = 101;
+    private static final int CONTINUED_LINE_INTERVAL = 100;
+    private static final int CONTINUED_LINE_SEQUENCE_1 = 52;
+    private static final int CONTINUED_LINE_SEQUENCE_2 = 53;
+
     MotionEventInjector mMotionEventInjector;
     IAccessibilityServiceClient mServiceInterface;
-    List<MotionEvent> mClickList = new ArrayList<>();
-    List<MotionEvent> mSecondClickList = new ArrayList<>();
+    List<GestureStep> mLineList = new ArrayList<>();
+    List<GestureStep> mClickList = new ArrayList<>();
+    List<GestureStep> mContinuedLineList1 = new ArrayList<>();
+    List<GestureStep> mContinuedLineList2 = new ArrayList<>();
+
+    MotionEvent mClickDownEvent;
+    MotionEvent mClickUpEvent;
+
     ArgumentCaptor<MotionEvent> mCaptor1 = ArgumentCaptor.forClass(MotionEvent.class);
     ArgumentCaptor<MotionEvent> mCaptor2 = ArgumentCaptor.forClass(MotionEvent.class);
     MessageCapturingHandler mMessageCapturingHandler;
-    MotionEventMatcher mClickEvent0Matcher;
-    MotionEventMatcher mClickEvent1Matcher;
-    MotionEventMatcher mClickEvent2Matcher;
-    MotionEventMatcher mSecondClickEvent0Matcher;
+    Matcher<MotionEvent> mIsLineStart;
+    Matcher<MotionEvent> mIsLineMiddle;
+    Matcher<MotionEvent> mIsLineEnd;
+    Matcher<MotionEvent> mIsClickDown;
+    Matcher<MotionEvent> mIsClickUp;
 
     @BeforeClass
     public static void oneTimeInitialization() {
@@ -99,226 +143,191 @@
             }
         });
         mMotionEventInjector = new MotionEventInjector(mMessageCapturingHandler);
-        mClickList.add(
-                MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, CLICK_X, CLICK_Y_START, 0));
-        mClickList.add(MotionEvent.obtain(
-                0, CLICK_DURATION, MotionEvent.ACTION_MOVE, CLICK_X, CLICK_Y_END, 0));
-        mClickList.add(MotionEvent.obtain(
-                0, CLICK_DURATION, MotionEvent.ACTION_UP, CLICK_X, CLICK_Y_END, 0));
-        for (int i = 0; i < mClickList.size(); i++) {
-            mClickList.get(i).setSource(MOTION_EVENT_SOURCE);
-        }
-
-        mClickEvent0Matcher = new MotionEventMatcher(mClickList.get(0));
-        mClickEvent1Matcher = new MotionEventMatcher(mClickList.get(1));
-        mClickEvent2Matcher = new MotionEventMatcher(mClickList.get(2));
-
-        mSecondClickList.add(MotionEvent.obtain(
-                0, 0, MotionEvent.ACTION_DOWN, SECOND_CLICK_X, SECOND_CLICK_Y, 0));
-        mSecondClickList.add(MotionEvent.obtain(
-                0, CLICK_DURATION, MotionEvent.ACTION_MOVE, SECOND_CLICK_X, CLICK_Y_END, 0));
-        mSecondClickList.add(MotionEvent.obtain(
-                0, CLICK_DURATION, MotionEvent.ACTION_UP, SECOND_CLICK_X, CLICK_Y_END, 0));
-        for (int i = 0; i < mSecondClickList.size(); i++) {
-            mSecondClickList.get(i).setSource(MOTION_EVENT_SOURCE);
-        }
-
-        mSecondClickEvent0Matcher = new MotionEventMatcher(mSecondClickList.get(0));
-
         mServiceInterface = mock(IAccessibilityServiceClient.class);
+
+        mLineList = createSimpleGestureFromPoints(0, 0, false, LINE_DURATION, LINE_START, LINE_END);
+        mClickList = createSimpleGestureFromPoints(
+                0, 0, false, CLICK_DURATION, CLICK_POINT, CLICK_POINT);
+        mContinuedLineList1 = createSimpleGestureFromPoints(CONTINUED_LINE_STROKE_ID_1, 0, true,
+                CONTINUED_LINE_INTERVAL, CONTINUED_LINE_START, CONTINUED_LINE_MID1);
+        mContinuedLineList2 = createSimpleGestureFromPoints(CONTINUED_LINE_STROKE_ID_2,
+                CONTINUED_LINE_STROKE_ID_1, false, CONTINUED_LINE_INTERVAL, CONTINUED_LINE_MID1,
+                CONTINUED_LINE_MID2, CONTINUED_LINE_END);
+
+        mClickDownEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, CLICK_POINT.x, CLICK_POINT.y, 0);
+        mClickDownEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+        mClickUpEvent = MotionEvent.obtain(0, CLICK_DURATION, ACTION_UP, CLICK_POINT.x,
+                CLICK_POINT.y, 0);
+        mClickUpEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+
+        mIsLineStart = allOf(IS_ACTION_DOWN, isAtPoint(LINE_START), hasStandardInitialization(),
+                hasTimeFromDown(0));
+        mIsLineMiddle = allOf(IS_ACTION_MOVE, isAtPoint(LINE_END), hasStandardInitialization(),
+                hasTimeFromDown(LINE_DURATION));
+        mIsLineEnd = allOf(IS_ACTION_UP, isAtPoint(LINE_END), hasStandardInitialization(),
+                hasTimeFromDown(LINE_DURATION));
+        mIsClickDown = allOf(IS_ACTION_DOWN, isAtPoint(CLICK_POINT), hasStandardInitialization(),
+                hasTimeFromDown(0));
+        mIsClickUp = allOf(IS_ACTION_UP, isAtPoint(CLICK_POINT), hasStandardInitialization(),
+                hasTimeFromDown(CLICK_DURATION));
     }
 
     @Test
     public void testInjectEvents_shouldEmergeInOrderWithCorrectTiming() throws RemoteException {
         EventStreamTransformation next = attachMockNext(mMotionEventInjector);
-        mMotionEventInjector.injectEvents(mClickList, mServiceInterface, SEQUENCE);
-        mMessageCapturingHandler.sendOneMessage(); // Process the event injection
+        injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE);
         verifyNoMoreInteractions(next);
         mMessageCapturingHandler.sendOneMessage(); // Send a motion event
 
-        verify(next).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(),
-                eq(WindowManagerPolicy.FLAG_PASS_TO_USER));
-        long gestureStart = mCaptor1.getValue().getDownTime();
-        mClickEvent0Matcher.offsetTimesBy(gestureStart);
-        mClickEvent1Matcher.offsetTimesBy(gestureStart);
-        mClickEvent2Matcher.offsetTimesBy(gestureStart);
-
-        verify(next).onMotionEvent(argThat(mClickEvent0Matcher), argThat(mClickEvent0Matcher),
-                eq(WindowManagerPolicy.FLAG_PASS_TO_USER));
+        verify(next).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), eq(FLAG_PASS_TO_USER));
+        verify(next).onMotionEvent(argThat(mIsLineStart), argThat(mIsLineStart),
+                eq(FLAG_PASS_TO_USER));
         verifyNoMoreInteractions(next);
         reset(next);
 
+        Matcher<MotionEvent> hasRightDownTime = hasDownTime(mCaptor1.getValue().getDownTime());
+
         mMessageCapturingHandler.sendOneMessage(); // Send a motion event
-        verify(next).onMotionEvent(argThat(mClickEvent1Matcher), argThat(mClickEvent1Matcher),
-                eq(WindowManagerPolicy.FLAG_PASS_TO_USER));
+        verify(next).onMotionEvent(argThat(allOf(mIsLineMiddle, hasRightDownTime)),
+                argThat(allOf(mIsLineMiddle, hasRightDownTime)), eq(FLAG_PASS_TO_USER));
         verifyNoMoreInteractions(next);
         reset(next);
 
         verifyZeroInteractions(mServiceInterface);
 
         mMessageCapturingHandler.sendOneMessage(); // Send a motion event
-        verify(next).onMotionEvent(argThat(mClickEvent2Matcher), argThat(mClickEvent2Matcher),
-                eq(WindowManagerPolicy.FLAG_PASS_TO_USER));
+        verify(next).onMotionEvent(argThat(allOf(mIsLineEnd, hasRightDownTime)),
+                argThat(allOf(mIsLineEnd, hasRightDownTime)), eq(FLAG_PASS_TO_USER));
         verifyNoMoreInteractions(next);
-        reset(next);
 
-        verify(mServiceInterface).onPerformGestureResult(SEQUENCE, true);
+        verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, true);
         verifyNoMoreInteractions(mServiceInterface);
     }
 
     @Test
-    public void testInjectEvents_eventWithManyPointers_shouldNotCrash() {
-        int manyPointersCount = 20;
-        MotionEvent.PointerCoords[] pointerCoords =
-                new MotionEvent.PointerCoords[manyPointersCount];
-        MotionEvent.PointerProperties[] pointerProperties =
-                new MotionEvent.PointerProperties[manyPointersCount];
-        for (int i = 0; i < manyPointersCount; i++) {
-            pointerProperties[i] = new MotionEvent.PointerProperties();
-            pointerProperties[i].id = i;
-            pointerProperties[i].toolType = MotionEvent.TOOL_TYPE_UNKNOWN;
-            pointerCoords[i] = new MotionEvent.PointerCoords();
-            pointerCoords[i].clear();
-            pointerCoords[i].pressure = 1.0f;
-            pointerCoords[i].size = 1.0f;
-            pointerCoords[i].x = i;
-            pointerCoords[i].y = i;
+    public void testInjectEvents_gestureWithTooManyPoints_shouldNotCrash() throws  Exception {
+        int tooManyPointsCount = 20;
+        TouchPoint[] startTouchPoints = new TouchPoint[tooManyPointsCount];
+        TouchPoint[] endTouchPoints = new TouchPoint[tooManyPointsCount];
+        for (int i = 0; i < tooManyPointsCount; i++) {
+            startTouchPoints[i] = new TouchPoint();
+            startTouchPoints[i].mIsStartOfPath = true;
+            startTouchPoints[i].mX = i;
+            startTouchPoints[i].mY = i;
+            endTouchPoints[i] = new TouchPoint();
+            endTouchPoints[i].mIsEndOfPath = true;
+            endTouchPoints[i].mX = i;
+            endTouchPoints[i].mY = i;
         }
-        List<MotionEvent> events = new ArrayList<>();
-        events.add(MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, manyPointersCount,
-                pointerProperties, pointerCoords, 0, 0,
-                1.0f, 1.0f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0));
-        events.add(MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, manyPointersCount,
-                pointerProperties, pointerCoords, 0, 0,
-                1.0f, 1.0f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0));
-        EventStreamTransformation next = attachMockNext(mMotionEventInjector);
-        mMotionEventInjector.injectEvents(events, mServiceInterface, SEQUENCE);
+        List<GestureStep> events = Arrays.asList(
+                new GestureStep(0, tooManyPointsCount, startTouchPoints),
+                new GestureStep(CLICK_DURATION, tooManyPointsCount, endTouchPoints));
+        attachMockNext(mMotionEventInjector);
+        injectEventsSync(events, mServiceInterface, CLICK_SEQUENCE);
         mMessageCapturingHandler.sendAllMessages();
-        verify(next, times(2)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt());
-        assertEquals(MotionEvent.ACTION_DOWN, mCaptor1.getAllValues().get(0).getActionMasked());
-        assertEquals(MotionEvent.ACTION_UP, mCaptor1.getAllValues().get(1).getActionMasked());
+        verify(mServiceInterface).onPerformGestureResult(eq(CLICK_SEQUENCE), anyBoolean());
     }
 
     @Test
     public void testRegularEvent_afterGestureComplete_shouldPassToNext() {
         EventStreamTransformation next = attachMockNext(mMotionEventInjector);
-        mMotionEventInjector.injectEvents(mClickList, mServiceInterface, SEQUENCE);
-        mMessageCapturingHandler.sendOneMessage(); // Process the event injection
+        injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE);
         mMessageCapturingHandler.sendAllMessages(); // Send all motion events
         reset(next);
-        mMotionEventInjector.onMotionEvent(mSecondClickList.get(0), mClickList.get(0), 0);
-        verify(next).onMotionEvent(argThat(mSecondClickEvent0Matcher),
-                argThat(mClickEvent0Matcher), eq(0));
+        mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0);
+        verify(next).onMotionEvent(argThat(mIsClickDown), argThat(mIsClickDown), eq(0));
     }
 
     @Test
     public void testInjectEvents_withRealGestureUnderway_shouldCancelRealAndPassInjected() {
         EventStreamTransformation next = attachMockNext(mMotionEventInjector);
-        mMotionEventInjector.onMotionEvent(mClickList.get(0), mClickList.get(0), 0);
-        mMotionEventInjector.injectEvents(mSecondClickList, mServiceInterface, SEQUENCE);
-        mMessageCapturingHandler.sendOneMessage(); // Process the event injection
+        mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0);
+        injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE);
 
         verify(next, times(2)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt());
-        assertTrue(mClickEvent0Matcher.matches(mCaptor1.getAllValues().get(0)));
-        assertEquals(MotionEvent.ACTION_CANCEL, mCaptor1.getAllValues().get(1).getActionMasked());
+        assertThat(mCaptor1.getAllValues().get(0), mIsClickDown);
+        assertThat(mCaptor1.getAllValues().get(1), IS_ACTION_CANCEL);
         reset(next);
 
         mMessageCapturingHandler.sendOneMessage(); // Send a motion event
-        verify(next).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(),
-                eq(WindowManagerPolicy.FLAG_PASS_TO_USER));
-        long gestureStart = mCaptor1.getValue().getDownTime();
-        mSecondClickEvent0Matcher.offsetTimesBy(gestureStart);
-
-        verify(next).onMotionEvent(argThat(mSecondClickEvent0Matcher),
-                argThat(mSecondClickEvent0Matcher), eq(WindowManagerPolicy.FLAG_PASS_TO_USER));
+        verify(next).onMotionEvent(
+                argThat(mIsLineStart), argThat(mIsLineStart), eq(FLAG_PASS_TO_USER));
     }
 
     @Test
     public void testInjectEvents_withRealMouseGestureUnderway_shouldContinueRealAndPassInjected() {
         EventStreamTransformation next = attachMockNext(mMotionEventInjector);
-        MotionEvent mouseEvent = MotionEvent.obtain(mClickList.get(0));
+        MotionEvent mouseEvent = MotionEvent.obtain(mClickDownEvent);
         mouseEvent.setSource(InputDevice.SOURCE_MOUSE);
-        MotionEventMatcher mouseEventMatcher = new MotionEventMatcher(mouseEvent);
+        MotionEventMatcher isMouseEvent = new MotionEventMatcher(mouseEvent);
         mMotionEventInjector.onMotionEvent(mouseEvent, mouseEvent, 0);
-        mMotionEventInjector.injectEvents(mSecondClickList, mServiceInterface, SEQUENCE);
-        mMessageCapturingHandler.sendOneMessage(); // Process the event injection
+        injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE);
 
         mMessageCapturingHandler.sendOneMessage(); // Send a motion event
         verify(next, times(2)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt());
-        assertTrue(mouseEventMatcher.matches(mCaptor1.getAllValues().get(0)));
-        mSecondClickEvent0Matcher.offsetTimesBy(mCaptor1.getAllValues().get(1).getDownTime());
-        assertTrue(mSecondClickEvent0Matcher.matches(mCaptor1.getAllValues().get(1)));
+        assertThat(mCaptor1.getAllValues().get(0), isMouseEvent);
+        assertThat(mCaptor1.getAllValues().get(1), mIsLineStart);
     }
 
     @Test
     public void testInjectEvents_withRealGestureFinished_shouldJustPassInjected() {
         EventStreamTransformation next = attachMockNext(mMotionEventInjector);
-        mMotionEventInjector.onMotionEvent(mClickList.get(0), mClickList.get(0), 0);
-        mMotionEventInjector.onMotionEvent(mClickList.get(1), mClickList.get(1), 0);
-        mMotionEventInjector.onMotionEvent(mClickList.get(2), mClickList.get(2), 0);
+        mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0);
+        mMotionEventInjector.onMotionEvent(mClickUpEvent, mClickUpEvent, 0);
 
-        mMotionEventInjector.injectEvents(mSecondClickList, mServiceInterface, SEQUENCE);
-        mMessageCapturingHandler.sendOneMessage(); // Process the event injection
-        verify(next, times(3)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt());
-
-        assertTrue(mClickEvent0Matcher.matches(mCaptor1.getAllValues().get(0)));
-        assertTrue(mClickEvent1Matcher.matches(mCaptor1.getAllValues().get(1)));
-        assertTrue(mClickEvent2Matcher.matches(mCaptor1.getAllValues().get(2)));
+        injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE);
+        verify(next, times(2)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt());
+        assertThat(mCaptor1.getAllValues().get(0), mIsClickDown);
+        assertThat(mCaptor1.getAllValues().get(1), mIsClickUp);
         reset(next);
 
         mMessageCapturingHandler.sendOneMessage(); // Send a motion event
-        verify(next).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(),
-                eq(WindowManagerPolicy.FLAG_PASS_TO_USER));
-        mSecondClickEvent0Matcher.offsetTimesBy(mCaptor1.getValue().getDownTime());
-        verify(next).onMotionEvent(argThat(mSecondClickEvent0Matcher),
-                argThat(mSecondClickEvent0Matcher), eq(WindowManagerPolicy.FLAG_PASS_TO_USER));
+        verify(next).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), eq(FLAG_PASS_TO_USER));
+        verify(next).onMotionEvent(
+                argThat(mIsLineStart), argThat(mIsLineStart), eq(FLAG_PASS_TO_USER));
     }
 
     @Test
     public void testOnMotionEvents_openInjectedGestureInProgress_shouldCancelAndNotifyAndPassReal()
             throws RemoteException {
         EventStreamTransformation next = attachMockNext(mMotionEventInjector);
-        mMotionEventInjector.injectEvents(mClickList, mServiceInterface, SEQUENCE);
-        mMessageCapturingHandler.sendOneMessage(); // Process the event injection
-
+        injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE);
         mMessageCapturingHandler.sendOneMessage(); // Send a motion event
-        mMotionEventInjector.onMotionEvent(mSecondClickList.get(0), mSecondClickList.get(0), 0);
+        mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0);
 
         verify(next, times(3)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt());
-        mClickEvent0Matcher.offsetTimesBy(mCaptor1.getAllValues().get(0).getDownTime());
-        assertTrue(mClickEvent0Matcher.matches(mCaptor1.getAllValues().get(0)));
-        assertEquals(MotionEvent.ACTION_CANCEL, mCaptor1.getAllValues().get(1).getActionMasked());
-        assertTrue(mSecondClickEvent0Matcher.matches(mCaptor1.getAllValues().get(2)));
-        verify(mServiceInterface).onPerformGestureResult(SEQUENCE, false);
+        assertThat(mCaptor1.getAllValues().get(0), mIsLineStart);
+        assertThat(mCaptor1.getAllValues().get(1), IS_ACTION_CANCEL);
+        assertThat(mCaptor1.getAllValues().get(2), mIsClickDown);
+        verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, false);
     }
 
     @Test
     public void testOnMotionEvents_closedInjectedGestureInProgress_shouldOnlyNotifyAndPassReal()
             throws RemoteException {
         EventStreamTransformation next = attachMockNext(mMotionEventInjector);
-        mClickList.add(MotionEvent.obtain(2 * CLICK_DURATION, 2 * CLICK_DURATION,
-                MotionEvent.ACTION_DOWN, CLICK_X, CLICK_Y_START, 0));
-        mMotionEventInjector.injectEvents(mClickList, mServiceInterface, SEQUENCE);
-        mMessageCapturingHandler.sendOneMessage(); // Process the event injection
+        // Tack a click down to the end of the line
+        TouchPoint clickTouchPoint = new TouchPoint();
+        clickTouchPoint.mIsStartOfPath = true;
+        clickTouchPoint.mX = CLICK_POINT.x;
+        clickTouchPoint.mY = CLICK_POINT.y;
+        mLineList.add(new GestureStep(0, 1, new TouchPoint[] {clickTouchPoint}));
+
+        injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE);
 
         // Send 3 motion events, leaving the extra down in the queue
         mMessageCapturingHandler.sendOneMessage();
         mMessageCapturingHandler.sendOneMessage();
         mMessageCapturingHandler.sendOneMessage();
 
-        mMotionEventInjector.onMotionEvent(mSecondClickList.get(0), mClickList.get(0), 0);
+        mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0);
 
         verify(next, times(4)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt());
-        long gestureStart = mCaptor1.getAllValues().get(0).getDownTime();
-        mClickEvent0Matcher.offsetTimesBy(gestureStart);
-        mClickEvent1Matcher.offsetTimesBy(gestureStart);
-        mClickEvent2Matcher.offsetTimesBy(gestureStart);
-        assertTrue(mClickEvent0Matcher.matches(mCaptor1.getAllValues().get(0)));
-        assertTrue(mClickEvent1Matcher.matches(mCaptor1.getAllValues().get(1)));
-        assertTrue(mClickEvent2Matcher.matches(mCaptor1.getAllValues().get(2)));
-        assertTrue(mSecondClickEvent0Matcher.matches(mCaptor1.getAllValues().get(3)));
-
-        verify(mServiceInterface).onPerformGestureResult(SEQUENCE, false);
+        assertThat(mCaptor1.getAllValues().get(0), mIsLineStart);
+        assertThat(mCaptor1.getAllValues().get(1), mIsLineMiddle);
+        assertThat(mCaptor1.getAllValues().get(2), mIsLineEnd);
+        assertThat(mCaptor1.getAllValues().get(3), mIsClickDown);
+        verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, false);
         assertFalse(mMessageCapturingHandler.hasMessages());
     }
 
@@ -326,105 +335,327 @@
     public void testInjectEvents_openInjectedGestureInProgress_shouldCancelAndNotifyAndPassNew()
             throws RemoteException {
         EventStreamTransformation next = attachMockNext(mMotionEventInjector);
-        mMotionEventInjector.injectEvents(mClickList, mServiceInterface, SEQUENCE);
-        mMessageCapturingHandler.sendOneMessage(); // Process the event injection
+        injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE);
         mMessageCapturingHandler.sendOneMessage(); // Send a motion event
 
-        mMotionEventInjector.injectEvents(mSecondClickList, mServiceInterface, SECOND_SEQUENCE);
-        mMessageCapturingHandler.sendLastMessage(); // Process the second event injection
+        injectEventsSync(mClickList, mServiceInterface, CLICK_SEQUENCE);
         mMessageCapturingHandler.sendOneMessage(); // Send a motion event
 
-        verify(mServiceInterface, times(1)).onPerformGestureResult(SEQUENCE, false);
+        verify(mServiceInterface, times(1)).onPerformGestureResult(LINE_SEQUENCE, false);
         verify(next, times(3)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt());
-        mClickEvent0Matcher.offsetTimesBy(mCaptor1.getAllValues().get(0).getDownTime());
-        assertTrue(mClickEvent0Matcher.matches(mCaptor1.getAllValues().get(0)));
-        assertEquals(MotionEvent.ACTION_CANCEL, mCaptor1.getAllValues().get(1).getActionMasked());
-        mSecondClickEvent0Matcher.offsetTimesBy(mCaptor1.getAllValues().get(2).getDownTime());
-        assertTrue(mSecondClickEvent0Matcher.matches(mCaptor1.getAllValues().get(2)));
+        assertThat(mCaptor1.getAllValues().get(0), mIsLineStart);
+        assertThat(mCaptor1.getAllValues().get(1), IS_ACTION_CANCEL);
+        assertThat(mCaptor1.getAllValues().get(2), mIsClickDown);
     }
 
     @Test
     public void testInjectEvents_closedInjectedGestureInProgress_shouldOnlyNotifyAndPassNew()
             throws RemoteException {
         EventStreamTransformation next = attachMockNext(mMotionEventInjector);
-        MotionEvent newEvent = MotionEvent.obtain(2 * CLICK_DURATION, 2 * CLICK_DURATION,
-                MotionEvent.ACTION_DOWN, CLICK_X, CLICK_Y_START, 0);
-        newEvent.setSource(mClickList.get(0).getSource());
-        mClickList.add(newEvent);
-        mMotionEventInjector.injectEvents(mClickList, mServiceInterface, SEQUENCE);
-        mMessageCapturingHandler.sendOneMessage(); // Process the event injection
+        // Tack a click down to the end of the line
+        TouchPoint clickTouchPoint = new TouchPoint();
+        clickTouchPoint.mIsStartOfPath = true;
+        clickTouchPoint.mX = CLICK_POINT.x;
+        clickTouchPoint.mY = CLICK_POINT.y;
+        mLineList.add(new GestureStep(0, 1, new TouchPoint[] {clickTouchPoint}));
+        injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE);
 
         // Send 3 motion events, leaving newEvent in the queue
         mMessageCapturingHandler.sendOneMessage();
         mMessageCapturingHandler.sendOneMessage();
         mMessageCapturingHandler.sendOneMessage();
 
-        mMotionEventInjector.injectEvents(mSecondClickList, mServiceInterface, SECOND_SEQUENCE);
-        mMessageCapturingHandler.sendLastMessage(); // Process the event injection
+        injectEventsSync(mClickList, mServiceInterface, CLICK_SEQUENCE);
         mMessageCapturingHandler.sendOneMessage(); // Send a motion event
 
-        verify(mServiceInterface).onPerformGestureResult(SEQUENCE, false);
+        verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, false);
         verify(next, times(4)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt());
-        long gestureStart = mCaptor1.getAllValues().get(0).getDownTime();
-        mClickEvent0Matcher.offsetTimesBy(gestureStart);
-        mClickEvent1Matcher.offsetTimesBy(gestureStart);
-        mClickEvent2Matcher.offsetTimesBy(gestureStart);
-        assertTrue(mClickEvent0Matcher.matches(mCaptor1.getAllValues().get(0)));
-        assertTrue(mClickEvent1Matcher.matches(mCaptor1.getAllValues().get(1)));
-        assertTrue(mClickEvent2Matcher.matches(mCaptor1.getAllValues().get(2)));
-        mSecondClickEvent0Matcher.offsetTimesBy(mCaptor1.getAllValues().get(3).getDownTime());
-        assertTrue(mSecondClickEvent0Matcher.matches(mCaptor1.getAllValues().get(3)));
+        assertThat(mCaptor1.getAllValues().get(0), mIsLineStart);
+        assertThat(mCaptor1.getAllValues().get(1), mIsLineMiddle);
+        assertThat(mCaptor1.getAllValues().get(2), mIsLineEnd);
+        assertThat(mCaptor1.getAllValues().get(3), mIsClickDown);
+    }
+
+    @Test
+    public void testContinuedGesture_continuationArrivesAfterDispatched_gestureCompletes()
+            throws Exception {
+        EventStreamTransformation next = attachMockNext(mMotionEventInjector);
+        injectEventsSync(mContinuedLineList1, mServiceInterface, CONTINUED_LINE_SEQUENCE_1);
+        mMessageCapturingHandler.sendAllMessages(); // Send all motion events
+        verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_1, true);
+        injectEventsSync(mContinuedLineList2, mServiceInterface, CONTINUED_LINE_SEQUENCE_2);
+        mMessageCapturingHandler.sendAllMessages(); // Send all motion events
+        verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_2, true);
+        verify(next, times(5)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt());
+        List<MotionEvent> events = mCaptor1.getAllValues();
+        long downTime = events.get(0).getDownTime();
+        assertThat(events.get(0), allOf(isAtPoint(CONTINUED_LINE_START), IS_ACTION_DOWN,
+                hasEventTime(downTime)));
+        assertThat(events, everyItem(hasDownTime(downTime)));
+        assertThat(events.get(1), allOf(isAtPoint(CONTINUED_LINE_MID1), IS_ACTION_MOVE,
+                hasEventTime(downTime + CONTINUED_LINE_INTERVAL)));
+        // Timing will restart when the gesture continues
+        long secondSequenceStart = events.get(2).getEventTime();
+        assertTrue(secondSequenceStart > events.get(1).getEventTime());
+        assertThat(events.get(2), allOf(isAtPoint(CONTINUED_LINE_MID2), IS_ACTION_MOVE));
+        assertThat(events.get(3), allOf(isAtPoint(CONTINUED_LINE_END), IS_ACTION_MOVE,
+                hasEventTime(secondSequenceStart + CONTINUED_LINE_INTERVAL)));
+        assertThat(events.get(4), allOf(isAtPoint(CONTINUED_LINE_END), IS_ACTION_UP,
+                hasEventTime(secondSequenceStart + CONTINUED_LINE_INTERVAL)));
+    }
+
+    @Test
+    public void testContinuedGesture_withTwoTouchPoints_gestureCompletes()
+            throws Exception {
+        // Run one point through the continued line backwards
+        int backLineId1 = 30;
+        int backLineId2 = 30;
+        List<GestureStep> continuedBackLineList1 = createSimpleGestureFromPoints(backLineId1, 0,
+                true, CONTINUED_LINE_INTERVAL, CONTINUED_LINE_END, CONTINUED_LINE_MID2);
+        List<GestureStep> continuedBackLineList2 = createSimpleGestureFromPoints(backLineId2,
+                backLineId1, false, CONTINUED_LINE_INTERVAL, CONTINUED_LINE_MID2,
+                CONTINUED_LINE_MID1, CONTINUED_LINE_START);
+        List<GestureStep> combinedLines1 = combineGestureSteps(
+                mContinuedLineList1, continuedBackLineList1);
+        List<GestureStep> combinedLines2 = combineGestureSteps(
+                mContinuedLineList2, continuedBackLineList2);
+
+        EventStreamTransformation next = attachMockNext(mMotionEventInjector);
+        injectEventsSync(combinedLines1, mServiceInterface, CONTINUED_LINE_SEQUENCE_1);
+        injectEventsSync(combinedLines2, mServiceInterface, CONTINUED_LINE_SEQUENCE_2);
+        mMessageCapturingHandler.sendAllMessages(); // Send all motion events
+        verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_1, true);
+        verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_2, true);
+        verify(next, times(7)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt());
+        List<MotionEvent> events = mCaptor1.getAllValues();
+        long downTime = events.get(0).getDownTime();
+        assertThat(events.get(0), allOf(
+                anyOf(isAtPoint(CONTINUED_LINE_END), isAtPoint(CONTINUED_LINE_START)),
+                IS_ACTION_DOWN, hasEventTime(downTime)));
+        assertThat(events, everyItem(hasDownTime(downTime)));
+        assertThat(events.get(1), allOf(containsPoints(CONTINUED_LINE_START, CONTINUED_LINE_END),
+                IS_ACTION_POINTER_DOWN, hasEventTime(downTime)));
+        assertThat(events.get(2), allOf(containsPoints(CONTINUED_LINE_MID1, CONTINUED_LINE_MID2),
+                IS_ACTION_MOVE, hasEventTime(downTime + CONTINUED_LINE_INTERVAL)));
+        assertThat(events.get(3), allOf(containsPoints(CONTINUED_LINE_MID1, CONTINUED_LINE_MID2),
+                IS_ACTION_MOVE, hasEventTime(downTime + CONTINUED_LINE_INTERVAL * 2)));
+        assertThat(events.get(4), allOf(containsPoints(CONTINUED_LINE_START, CONTINUED_LINE_END),
+                IS_ACTION_MOVE, hasEventTime(downTime + CONTINUED_LINE_INTERVAL * 3)));
+        assertThat(events.get(5), allOf(containsPoints(CONTINUED_LINE_START, CONTINUED_LINE_END),
+                IS_ACTION_POINTER_UP, hasEventTime(downTime + CONTINUED_LINE_INTERVAL * 3)));
+        assertThat(events.get(6), allOf(
+                anyOf(isAtPoint(CONTINUED_LINE_END), isAtPoint(CONTINUED_LINE_START)),
+                IS_ACTION_UP, hasEventTime(downTime + CONTINUED_LINE_INTERVAL * 3)));
+    }
+
+
+    @Test
+    public void testContinuedGesture_continuationArrivesWhileDispatching_gestureCompletes()
+            throws Exception {
+        EventStreamTransformation next = attachMockNext(mMotionEventInjector);
+        injectEventsSync(mContinuedLineList1, mServiceInterface, CONTINUED_LINE_SEQUENCE_1);
+        mMessageCapturingHandler.sendOneMessage(); // Send a motion event
+        injectEventsSync(mContinuedLineList2, mServiceInterface, CONTINUED_LINE_SEQUENCE_2);
+        mMessageCapturingHandler.sendAllMessages(); // Send all motion events
+        verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_1, true);
+        verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_2, true);
+        verify(next, times(5)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt());
+        List<MotionEvent> events = mCaptor1.getAllValues();
+        long downTime = events.get(0).getDownTime();
+        assertThat(events.get(0), allOf(isAtPoint(CONTINUED_LINE_START), IS_ACTION_DOWN,
+                hasEventTime(downTime)));
+        assertThat(events, everyItem(hasDownTime(downTime)));
+        assertThat(events.get(1), allOf(isAtPoint(CONTINUED_LINE_MID1), IS_ACTION_MOVE,
+                hasEventTime(downTime + CONTINUED_LINE_INTERVAL)));
+        assertThat(events.get(2), allOf(isAtPoint(CONTINUED_LINE_MID2), IS_ACTION_MOVE,
+                hasEventTime(downTime + CONTINUED_LINE_INTERVAL * 2)));
+        assertThat(events.get(3), allOf(isAtPoint(CONTINUED_LINE_END), IS_ACTION_MOVE,
+                hasEventTime(downTime + CONTINUED_LINE_INTERVAL * 3)));
+        assertThat(events.get(4), allOf(isAtPoint(CONTINUED_LINE_END), IS_ACTION_UP,
+                hasEventTime(downTime + CONTINUED_LINE_INTERVAL * 3)));
+    }
+
+    @Test
+    public void testContinuedGesture_twoContinuationsArriveWhileDispatching_gestureCompletes()
+            throws Exception {
+        EventStreamTransformation next = attachMockNext(mMotionEventInjector);
+        injectEventsSync(mContinuedLineList1, mServiceInterface, CONTINUED_LINE_SEQUENCE_1);
+        // Continue line again
+        List<GestureStep> continuedLineList2 = createSimpleGestureFromPoints(
+                CONTINUED_LINE_STROKE_ID_2, CONTINUED_LINE_STROKE_ID_1, true,
+                CONTINUED_LINE_INTERVAL, CONTINUED_LINE_MID1,
+                CONTINUED_LINE_MID2, CONTINUED_LINE_END);
+        // Finish line by backtracking
+        int strokeId3 = CONTINUED_LINE_STROKE_ID_2 + 1;
+        int sequence3 = CONTINUED_LINE_SEQUENCE_2 + 1;
+        List<GestureStep> continuedLineList3 = createSimpleGestureFromPoints(strokeId3,
+                CONTINUED_LINE_STROKE_ID_2, false, CONTINUED_LINE_INTERVAL, CONTINUED_LINE_END,
+                CONTINUED_LINE_MID2);
+
+        mMessageCapturingHandler.sendOneMessage(); // Send a motion event
+        injectEventsSync(continuedLineList2, mServiceInterface, CONTINUED_LINE_SEQUENCE_2);
+        injectEventsSync(continuedLineList3, mServiceInterface, sequence3);
+        mMessageCapturingHandler.sendAllMessages(); // Send all motion events
+        verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_1, true);
+        verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_2, true);
+        verify(mServiceInterface).onPerformGestureResult(sequence3, true);
+        verify(next, times(6)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt());
+        List<MotionEvent> events = mCaptor1.getAllValues();
+        long downTime = events.get(0).getDownTime();
+        assertThat(events.get(0), allOf(isAtPoint(CONTINUED_LINE_START), IS_ACTION_DOWN,
+                hasEventTime(downTime)));
+        assertThat(events, everyItem(hasDownTime(downTime)));
+        assertThat(events.get(1), allOf(isAtPoint(CONTINUED_LINE_MID1), IS_ACTION_MOVE,
+                hasEventTime(downTime + CONTINUED_LINE_INTERVAL)));
+        assertThat(events.get(2), allOf(isAtPoint(CONTINUED_LINE_MID2), IS_ACTION_MOVE,
+                hasEventTime(downTime + CONTINUED_LINE_INTERVAL * 2)));
+        assertThat(events.get(3), allOf(isAtPoint(CONTINUED_LINE_END), IS_ACTION_MOVE,
+                hasEventTime(downTime + CONTINUED_LINE_INTERVAL * 3)));
+        assertThat(events.get(4), allOf(isAtPoint(CONTINUED_LINE_MID2), IS_ACTION_MOVE,
+                hasEventTime(downTime + CONTINUED_LINE_INTERVAL * 4)));
+        assertThat(events.get(5), allOf(isAtPoint(CONTINUED_LINE_MID2), IS_ACTION_UP,
+                hasEventTime(downTime + CONTINUED_LINE_INTERVAL * 4)));
+    }
+
+    @Test
+    public void testContinuedGesture_nonContinuingGestureArrivesDuringDispatch_gestureCanceled()
+            throws Exception {
+        EventStreamTransformation next = attachMockNext(mMotionEventInjector);
+        injectEventsSync(mContinuedLineList1, mServiceInterface, CONTINUED_LINE_SEQUENCE_1);
+        mMessageCapturingHandler.sendOneMessage(); // Send a motion event
+        injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE);
+        mMessageCapturingHandler.sendAllMessages(); // Send all motion events
+        verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_1, false);
+        verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, true);
+        verify(next, times(5)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt());
+        List<MotionEvent> events = mCaptor1.getAllValues();
+        assertThat(events.get(0), allOf(isAtPoint(CONTINUED_LINE_START), IS_ACTION_DOWN));
+        assertThat(events.get(1), IS_ACTION_CANCEL);
+        assertThat(events.get(2), allOf(isAtPoint(LINE_START), IS_ACTION_DOWN));
+        assertThat(events.get(3), allOf(isAtPoint(LINE_END), IS_ACTION_MOVE));
+        assertThat(events.get(4), allOf(isAtPoint(LINE_END), IS_ACTION_UP));
+    }
+
+    @Test
+    public void testContinuedGesture_nonContinuingGestureArrivesAfterDispatch_gestureCanceled()
+            throws Exception {
+        EventStreamTransformation next = attachMockNext(mMotionEventInjector);
+        injectEventsSync(mContinuedLineList1, mServiceInterface, CONTINUED_LINE_SEQUENCE_1);
+        mMessageCapturingHandler.sendAllMessages(); // Send all motion events
+        injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE);
+        mMessageCapturingHandler.sendAllMessages(); // Send all motion events
+        verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_1, true);
+        verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, true);
+        verify(next, times(6)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt());
+        List<MotionEvent> events = mCaptor1.getAllValues();
+        assertThat(events.get(0), allOf(isAtPoint(CONTINUED_LINE_START), IS_ACTION_DOWN));
+        assertThat(events.get(1), allOf(isAtPoint(CONTINUED_LINE_MID1), IS_ACTION_MOVE));
+        assertThat(events.get(2), IS_ACTION_CANCEL);
+        assertThat(events.get(3), allOf(isAtPoint(LINE_START), IS_ACTION_DOWN));
+        assertThat(events.get(4), allOf(isAtPoint(LINE_END), IS_ACTION_MOVE));
+        assertThat(events.get(5), allOf(isAtPoint(LINE_END), IS_ACTION_UP));
+    }
+
+    @Test
+    public void testContinuedGesture_misMatchedContinuationArrives_bothGesturesCanceled()
+            throws Exception {
+        EventStreamTransformation next = attachMockNext(mMotionEventInjector);
+        injectEventsSync(mContinuedLineList1, mServiceInterface, CONTINUED_LINE_SEQUENCE_1);
+        mMessageCapturingHandler.sendAllMessages(); // Send all motion events
+        verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_1, true);
+        List<GestureStep> discontinuousGesture = mContinuedLineList2
+                .subList(1, mContinuedLineList2.size());
+        injectEventsSync(discontinuousGesture, mServiceInterface, CONTINUED_LINE_SEQUENCE_2);
+        mMessageCapturingHandler.sendAllMessages(); // Send all motion events
+        verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_2, false);
+        verify(next, times(3)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt());
+        List<MotionEvent> events = mCaptor1.getAllValues();
+        assertThat(events.get(0), allOf(isAtPoint(CONTINUED_LINE_START), IS_ACTION_DOWN));
+        assertThat(events.get(1), allOf(isAtPoint(CONTINUED_LINE_MID1), IS_ACTION_MOVE));
+        assertThat(events.get(2), allOf(isAtPoint(CONTINUED_LINE_MID1), IS_ACTION_CANCEL));
+    }
+
+    @Test
+    public void testContinuedGesture_continuationArrivesFromOtherService_bothGesturesCanceled()
+            throws Exception {
+        EventStreamTransformation next = attachMockNext(mMotionEventInjector);
+        IAccessibilityServiceClient otherService = mock(IAccessibilityServiceClient.class);
+        injectEventsSync(mContinuedLineList1, mServiceInterface, CONTINUED_LINE_SEQUENCE_1);
+        mMessageCapturingHandler.sendOneMessage(); // Send a motion events
+        injectEventsSync(mContinuedLineList2, otherService, CONTINUED_LINE_SEQUENCE_2);
+        mMessageCapturingHandler.sendAllMessages(); // Send all motion events
+        verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_1, false);
+        verify(otherService).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_2, false);
+        verify(next, times(2)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt());
+        List<MotionEvent> events = mCaptor1.getAllValues();
+        assertThat(events.get(0), allOf(isAtPoint(CONTINUED_LINE_START), IS_ACTION_DOWN));
+        assertThat(events.get(1), IS_ACTION_CANCEL);
+    }
+
+    @Test
+    public void testContinuedGesture_realGestureArrivesInBetween_getsCanceled()
+            throws Exception {
+        EventStreamTransformation next = attachMockNext(mMotionEventInjector);
+        injectEventsSync(mContinuedLineList1, mServiceInterface, CONTINUED_LINE_SEQUENCE_1);
+        mMessageCapturingHandler.sendAllMessages(); // Send all motion events
+        verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_1, true);
+
+        mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0);
+
+        injectEventsSync(mContinuedLineList2, mServiceInterface, CONTINUED_LINE_SEQUENCE_2);
+        mMessageCapturingHandler.sendAllMessages(); // Send all motion events
+        verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_2, false);
+        verify(next, times(4)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt());
+        List<MotionEvent> events = mCaptor1.getAllValues();
+        assertThat(events.get(0), allOf(isAtPoint(CONTINUED_LINE_START), IS_ACTION_DOWN));
+        assertThat(events.get(1), allOf(isAtPoint(CONTINUED_LINE_MID1), IS_ACTION_MOVE));
+        assertThat(events.get(2), IS_ACTION_CANCEL);
+        assertThat(events.get(3), allOf(isAtPoint(CLICK_POINT), IS_ACTION_DOWN));
     }
 
     @Test
     public void testClearEvents_realGestureInProgress_shouldForgetAboutGesture() {
         EventStreamTransformation next = attachMockNext(mMotionEventInjector);
-        mMotionEventInjector.onMotionEvent(mClickList.get(0), mClickList.get(0), 0);
+        mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0);
         mMotionEventInjector.clearEvents(MOTION_EVENT_SOURCE);
-        mMotionEventInjector.injectEvents(mSecondClickList, mServiceInterface, SEQUENCE);
-        mMessageCapturingHandler.sendOneMessage(); // Process the event injection
+        injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE);
         mMessageCapturingHandler.sendOneMessage(); // Send a motion event
 
         verify(next, times(2)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt());
-        assertTrue(mClickEvent0Matcher.matches(mCaptor1.getAllValues().get(0)));
-        mSecondClickEvent0Matcher.offsetTimesBy(mCaptor1.getAllValues().get(1).getDownTime());
-        assertTrue(mSecondClickEvent0Matcher.matches(mCaptor1.getAllValues().get(1)));
+        assertThat(mCaptor1.getAllValues().get(0), mIsClickDown);
+        assertThat(mCaptor1.getAllValues().get(1), mIsLineStart);
     }
 
     @Test
     public void testClearEventsOnOtherSource_realGestureInProgress_shouldNotForgetAboutGesture() {
         EventStreamTransformation next = attachMockNext(mMotionEventInjector);
-        mMotionEventInjector.onMotionEvent(mClickList.get(0), mClickList.get(0), 0);
+        mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0);
         mMotionEventInjector.clearEvents(OTHER_EVENT_SOURCE);
-        mMotionEventInjector.injectEvents(mSecondClickList, mServiceInterface, SECOND_SEQUENCE);
-        mMessageCapturingHandler.sendOneMessage(); // Process the event injection
+        injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE);
         mMessageCapturingHandler.sendOneMessage(); // Send a motion event
 
         verify(next, times(3)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt());
-        assertTrue(mClickEvent0Matcher.matches(mCaptor1.getAllValues().get(0)));
-        assertEquals(MotionEvent.ACTION_CANCEL, mCaptor1.getAllValues().get(1).getActionMasked());
-        mSecondClickEvent0Matcher.offsetTimesBy(mCaptor1.getAllValues().get(2).getDownTime());
-        assertTrue(mSecondClickEvent0Matcher.matches(mCaptor1.getAllValues().get(2)));
+        assertThat(mCaptor1.getAllValues().get(0), mIsClickDown);
+        assertThat(mCaptor1.getAllValues().get(1), IS_ACTION_CANCEL);
+        assertThat(mCaptor1.getAllValues().get(2), mIsLineStart);
     }
 
     @Test
     public void testOnDestroy_shouldCancelGestures() throws RemoteException {
         mMotionEventInjector.onDestroy();
-        mMotionEventInjector.injectEvents(mClickList, mServiceInterface, SEQUENCE);
-        mMessageCapturingHandler.sendOneMessage(); // Process the event injection
-        verify(mServiceInterface).onPerformGestureResult(SEQUENCE, false);
+        injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE);
+        verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, false);
     }
 
     @Test
     public void testInjectEvents_withNoNext_shouldCancel() throws RemoteException {
-        mMotionEventInjector.injectEvents(mClickList, mServiceInterface, SEQUENCE);
-        mMessageCapturingHandler.sendOneMessage(); // Process the event injection
-        verify(mServiceInterface).onPerformGestureResult(SEQUENCE, false);
+        injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE);
+        verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, false);
     }
 
     @Test
     public void testOnMotionEvent_withNoNext_shouldNotCrash() {
-        mMotionEventInjector.onMotionEvent(mClickList.get(0), mClickList.get(0), 0);
+        mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0);
     }
 
     @Test
@@ -455,6 +686,52 @@
         mMotionEventInjector.onAccessibilityEvent(event);
     }
 
+    private void injectEventsSync(List<GestureStep> gestureSteps,
+            IAccessibilityServiceClient serviceInterface, int sequence) {
+        mMotionEventInjector.injectEvents(gestureSteps, serviceInterface, sequence);
+        // Dispatch the message sent by the injector. Our simple handler doesn't guarantee stuff
+        // happens in order.
+        mMessageCapturingHandler.sendLastMessage();
+    }
+
+    private List<GestureStep> createSimpleGestureFromPoints(int strokeId, int continuedStrokeId,
+            boolean continued, long interval, Point... points) {
+        List<GestureStep> gesture = new ArrayList<>(points.length);
+        TouchPoint[] touchPoints = new TouchPoint[1];
+        touchPoints[0] = new TouchPoint();
+        for (int i = 0; i < points.length; i++) {
+            touchPoints[0].mX = points[i].x;
+            touchPoints[0].mY = points[i].y;
+            touchPoints[0].mIsStartOfPath = ((i == 0) && (continuedStrokeId <= 0));
+            touchPoints[0].mContinuedStrokeId = continuedStrokeId;
+            touchPoints[0].mStrokeId = strokeId;
+            touchPoints[0].mIsEndOfPath = ((i == points.length - 1) && !continued);
+            gesture.add(new GestureStep(interval * i, 1, touchPoints));
+        }
+        return gesture;
+    }
+
+    List<GestureStep> combineGestureSteps(List<GestureStep> list1, List<GestureStep> list2) {
+        assertEquals(list1.size(), list2.size());
+        List<GestureStep> gesture = new ArrayList<>(list1.size());
+        for (int i = 0; i < list1.size(); i++) {
+            int numPoints1 = list1.get(i).numTouchPoints;
+            int numPoints2 = list2.get(i).numTouchPoints;
+            TouchPoint[] touchPoints = new TouchPoint[numPoints1 + numPoints2];
+            for (int j = 0; j < numPoints1; j++) {
+                touchPoints[j] = new TouchPoint();
+                touchPoints[j].copyFrom(list1.get(i).touchPoints[j]);
+            }
+            for (int j = 0; j < numPoints2; j++) {
+                touchPoints[numPoints1 + j] = new TouchPoint();
+                touchPoints[numPoints1 + j].copyFrom(list2.get(i).touchPoints[j]);
+            }
+            gesture.add(new GestureStep(list1.get(i).timeSinceGestureStart,
+                    numPoints1 + numPoints2, touchPoints));
+        }
+        return gesture;
+    }
+
     private EventStreamTransformation attachMockNext(MotionEventInjector motionEventInjector) {
         EventStreamTransformation next = mock(EventStreamTransformation.class);
         motionEventInjector.setNext(next);
@@ -506,4 +783,126 @@
             return false;
         }
     }
+
+    private static class MotionEventActionMatcher extends TypeSafeMatcher<MotionEvent> {
+        int mAction;
+
+        MotionEventActionMatcher(int action) {
+            super();
+            mAction = action;
+        }
+
+        @Override
+        protected boolean matchesSafely(MotionEvent motionEvent) {
+            return motionEvent.getActionMasked() == mAction;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("Matching to action " + mAction);
+        }
+    }
+
+    private static TypeSafeMatcher<MotionEvent> isAtPoint(final Point point) {
+        return new TypeSafeMatcher<MotionEvent>() {
+            @Override
+            protected boolean matchesSafely(MotionEvent event) {
+                return ((event.getX() == point.x) && (event.getY() == point.y));
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("Is at point " + point);
+            }
+        };
+    }
+
+    private static TypeSafeMatcher<MotionEvent> containsPoints(final Point... points) {
+        return new TypeSafeMatcher<MotionEvent>() {
+            @Override
+            protected boolean matchesSafely(MotionEvent event) {
+                MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
+                for (int i = 0; i < points.length; i++) {
+                    boolean havePoint = false;
+                    for (int j = 0; j < points.length; j++) {
+                        event.getPointerCoords(j, coords);
+                        if ((points[i].x == coords.x) && (points[i].y == coords.y)) {
+                            havePoint = true;
+                        }
+                    }
+                    if (!havePoint) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("Contains points " + points);
+            }
+        };
+    }
+
+    private static TypeSafeMatcher<MotionEvent> hasDownTime(final long downTime) {
+        return new TypeSafeMatcher<MotionEvent>() {
+            @Override
+            protected boolean matchesSafely(MotionEvent event) {
+                return event.getDownTime() == downTime;
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("Down time = " + downTime);
+            }
+        };
+    }
+
+    private static TypeSafeMatcher<MotionEvent> hasEventTime(final long eventTime) {
+        return new TypeSafeMatcher<MotionEvent>() {
+            @Override
+            protected boolean matchesSafely(MotionEvent event) {
+                return event.getEventTime() == eventTime;
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("Event time = " + eventTime);
+            }
+        };
+    }
+
+    private static TypeSafeMatcher<MotionEvent> hasTimeFromDown(final long timeFromDown) {
+        return new TypeSafeMatcher<MotionEvent>() {
+            @Override
+            protected boolean matchesSafely(MotionEvent event) {
+                return (event.getEventTime() - event.getDownTime()) == timeFromDown;
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("Time from down to event times = " + timeFromDown);
+            }
+        };
+    }
+
+    private static TypeSafeMatcher<MotionEvent> hasStandardInitialization() {
+        return new TypeSafeMatcher<MotionEvent>() {
+            @Override
+            protected boolean matchesSafely(MotionEvent event) {
+                return (0 == event.getActionIndex()) && (0 == event.getDeviceId())
+                        && (0 == event.getEdgeFlags()) && (0 == event.getFlags())
+                        && (0 == event.getMetaState()) && (0F == event.getOrientation())
+                        && (0F == event.getTouchMajor()) && (0F == event.getTouchMinor())
+                        && (1F == event.getXPrecision()) && (1F == event.getYPrecision())
+                        && (1 == event.getPointerCount()) && (1F == event.getPressure())
+                        && (InputDevice.SOURCE_TOUCHSCREEN == event.getSource());
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("Has standard values for all parameters");
+            }
+        };
+    }
 }
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 2d21c08..3ad40758 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -22,15 +22,20 @@
 import android.app.admin.DevicePolicyManagerInternal;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.graphics.Color;
 import android.net.IIpConnectivityMetrics;
+import android.content.pm.UserInfo;
 import android.net.wifi.WifiInfo;
 import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -2447,6 +2452,110 @@
         assertEquals(-1, dpm.getLastNetworkLogRetrievalTime());
     }
 
+    public void testGetBindDeviceAdminTargetUsers() throws Exception {
+        // Setup device owner.
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        setupDeviceOwner();
+
+        // Only device owner is setup, the result list should be empty.
+        List<UserHandle> targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
+        MoreAsserts.assertEmpty(targetUsers);
+
+        // Setup a managed profile managed by the same admin.
+        final int MANAGED_PROFILE_USER_ID = 15;
+        final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 20456);
+        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
+
+        // Add a secondary user, it should never talk with.
+        final int ANOTHER_USER_ID = 36;
+        mContext.addUser(ANOTHER_USER_ID, 0);
+
+        // Calling from device owner admin, the result list should just contain the managed
+        // profile user id.
+        targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
+        MoreAsserts.assertContentsInAnyOrder(targetUsers, UserHandle.of(MANAGED_PROFILE_USER_ID));
+
+        // Calling from managed profile admin, the result list should just contain the system
+        // user id.
+        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
+        targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
+        MoreAsserts.assertContentsInAnyOrder(targetUsers, UserHandle.SYSTEM);
+    }
+
+    public void testGetBindDeviceAdminTargetUsers_differentPackage() throws Exception {
+        // Setup a device owner.
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        setupDeviceOwner();
+
+        // Set up a managed profile managed by different package.
+        final int MANAGED_PROFILE_USER_ID = 15;
+        final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 20456);
+        final ComponentName adminDifferentPackage =
+                new ComponentName("another.package", "whatever.class");
+        addManagedProfile(adminDifferentPackage, MANAGED_PROFILE_ADMIN_UID, admin2);
+
+        // Calling from device owner admin, we should get zero bind device admin target users as
+        // their packages are different.
+        List<UserHandle> targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
+        MoreAsserts.assertEmpty(targetUsers);
+
+        // Calling from managed profile admin, we should still get zero target users for the same
+        // reason.
+        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
+        targetUsers = dpm.getBindDeviceAdminTargetUsers(adminDifferentPackage);
+        MoreAsserts.assertEmpty(targetUsers);
+    }
+
+    public void testIsDeviceManaged() throws Exception {
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        setupDeviceOwner();
+
+        // The device owner itself, any uid holding MANAGE_USERS permission and the system can
+        // find out that the device has a device owner.
+        assertTrue(dpm.isDeviceManaged());
+        mContext.binder.callingUid = 1234567;
+        mContext.callerPermissions.add(permission.MANAGE_USERS);
+        assertTrue(dpm.isDeviceManaged());
+        mContext.callerPermissions.remove(permission.MANAGE_USERS);
+        mContext.binder.clearCallingIdentity();
+        assertTrue(dpm.isDeviceManaged());
+
+        clearDeviceOwner();
+
+        // Any uid holding MANAGE_USERS permission and the system can find out that the device does
+        // not have a device owner.
+        mContext.binder.callingUid = 1234567;
+        mContext.callerPermissions.add(permission.MANAGE_USERS);
+        assertFalse(dpm.isDeviceManaged());
+        mContext.callerPermissions.remove(permission.MANAGE_USERS);
+        mContext.binder.clearCallingIdentity();
+        assertFalse(dpm.isDeviceManaged());
+    }
+
+    public void testDeviceOwnerOrganizationName() throws Exception {
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        setupDeviceOwner();
+
+        dpm.setOrganizationName(admin1, "organization");
+
+        // Device owner can retrieve organization managing the device.
+        assertEquals("organization", dpm.getDeviceOwnerOrganizationName());
+
+        // Any uid holding MANAGE_USERS permission can retrieve organization managing the device.
+        mContext.binder.callingUid = 1234567;
+        mContext.callerPermissions.add(permission.MANAGE_USERS);
+        assertEquals("organization", dpm.getDeviceOwnerOrganizationName());
+        mContext.callerPermissions.remove(permission.MANAGE_USERS);
+
+        // System can retrieve organization managing the device.
+        mContext.binder.clearCallingIdentity();
+        assertEquals("organization", dpm.getDeviceOwnerOrganizationName());
+
+        // Removing the device owner clears the organization managing the device.
+        clearDeviceOwner();
+        assertNull(dpm.getDeviceOwnerOrganizationName());
+    }
+
     private void setUserSetupCompleteForUser(boolean isUserSetupComplete, int userhandle) {
         when(mContext.settings.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0,
                 userhandle)).thenReturn(isUserSetupComplete ? 1 : 0);
@@ -2458,4 +2567,22 @@
         assertEquals("isProvisioningAllowed(" + action + ") returning unexpected result", expected,
                 dpm.isProvisioningAllowed(action));
     }
+
+    /**
+     * Setup a managed profile with the specified admin and its uid.
+     * @param admin ComponentName that's visible to the test code, which doesn't have to exist.
+     * @param adminUid uid of the admin package.
+     * @param copyFromAdmin package information for {@code admin} will be built based on this
+     *     component's information.
+     */
+    private void addManagedProfile(
+            ComponentName admin, int adminUid, ComponentName copyFromAdmin) throws Exception {
+        final int userId = UserHandle.getUserId(adminUid);
+        mContext.addUser(userId, UserInfo.FLAG_MANAGED_PROFILE, UserHandle.USER_SYSTEM);
+        mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS);
+        setUpPackageManagerForFakeAdmin(admin, adminUid, copyFromAdmin);
+        dpm.setActiveAdmin(admin, false, userId);
+        assertTrue(dpm.setProfileOwner(admin, null, userId));
+        mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index d74c6dc..1247b2d 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -16,8 +16,6 @@
 
 package com.android.server.devicepolicy;
 
-import com.android.internal.widget.LockPatternUtils;
-
 import android.app.IActivityManager;
 import android.app.NotificationManager;
 import android.app.backup.IBackupManager;
@@ -47,6 +45,8 @@
 import android.test.mock.MockContext;
 import android.view.IWindowManager;
 
+import com.android.internal.widget.LockPatternUtils;
+
 import org.junit.Assert;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
@@ -324,16 +324,21 @@
         contentResolver = new MockContentResolver();
 
         // Add the system user
-        systemUserDataDir = addUser(UserHandle.USER_SYSTEM, UserInfo.FLAG_PRIMARY);
+        systemUserDataDir =
+                addUser(UserHandle.USER_SYSTEM, UserInfo.FLAG_PRIMARY, UserHandle.USER_SYSTEM);
 
         // System user is always running.
         setUserRunning(UserHandle.USER_SYSTEM, true);
     }
 
     public File addUser(int userId, int flags) {
+        return addUser(userId, flags, UserInfo.NO_PROFILE_GROUP_ID);
+    }
 
+    public File addUser(int userId, int flags, int profileGroupId) {
         // Set up (default) UserInfo for CALLER_USER_HANDLE.
         final UserInfo uh = new UserInfo(userId, "user" + userId, flags);
+        uh.profileGroupId = profileGroupId;
         when(userManager.getUserInfo(eq(userId))).thenReturn(uh);
 
         mUserInfos.add(uh);
@@ -345,12 +350,7 @@
                     @Override
                     public UserInfo answer(InvocationOnMock invocation) throws Throwable {
                         final int userId = (int) invocation.getArguments()[0];
-                        for (UserInfo ui : mUserInfos) {
-                            if (ui.id == userId) {
-                                return ui;
-                            }
-                        }
-                        return null;
+                        return getUserInfo(userId);
                     }
                 }
         );
@@ -369,16 +369,13 @@
                     public int[] answer(InvocationOnMock invocation) throws Throwable {
                         final int userId = (int) invocation.getArguments()[0];
                         List<UserInfo> profiles = getProfiles(userId);
-                        int[] results = new int[profiles.size()];
-                        for (int i = 0; i < results.length; i++) {
-                            results[i] = profiles.get(i).id;
-                        }
-                        return results;
+                        return profiles.stream()
+                                .mapToInt(profile -> profile.id)
+                                .toArray();
                     }
                 }
         );
 
-
         // Create a data directory.
         final File dir = new File(dataDir, "user" + userId);
         DpmTestUtils.clearDir(dir);
@@ -387,6 +384,15 @@
         return dir;
     }
 
+    private UserInfo getUserInfo(int userId) {
+        for (UserInfo ui : mUserInfos) {
+            if (ui.id == userId) {
+                return ui;
+            }
+        }
+        return null;
+    }
+
     private List<UserInfo> getProfiles(int userId) {
         final ArrayList<UserInfo> ret = new ArrayList<UserInfo>();
         UserInfo parent = null;
@@ -401,9 +407,6 @@
         }
         ret.add(parent);
         for (UserInfo ui : mUserInfos) {
-            if (ui.id == userId) {
-                continue;
-            }
             if (ui.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
                     && ui.profileGroupId == parent.profileGroupId) {
                 ret.add(ui);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
index b4b74b3..db27f72 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -101,6 +101,13 @@
                 admin);
     }
 
+    protected void setUpPackageManagerForFakeAdmin(ComponentName admin, int packageUid,
+            ComponentName copyFromAdmin)
+            throws Exception {
+        setUpPackageManagerForFakeAdmin(admin, packageUid,
+                /* enabledSetting =*/ null, /* appTargetSdk = */ null, copyFromAdmin);
+    }
+
     /**
      * Set up a component in the mock package manager to be an active admin.
      *
@@ -118,7 +125,6 @@
                 mRealTestContext.getPackageManager().getApplicationInfo(
                         copyFromAdmin.getPackageName(),
                         PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS));
-
         ai.enabledSetting = enabledSetting == null
                 ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
                 : enabledSetting;
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 9f01773..99af9e8 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -376,6 +376,7 @@
 
         @Override
         boolean injectIsActivityEnabledAndExported(ComponentName activity, @UserIdInt int userId) {
+            assertNotNull(activity);
             return mEnabledActivityChecker.test(activity, userId);
         }
 
@@ -416,6 +417,11 @@
             // During tests, WTF is fatal.
             fail(message + "  exception: " + th + "\n" + Log.getStackTraceString(th));
         }
+
+        @Override
+        void verifyError() {
+            fail("Verify error");
+        }
     }
 
     /** ShortcutManager with injection override methods. */
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java
index 379d4fe..1188bb7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java
@@ -27,12 +27,16 @@
 import android.util.ArraySet;
 
 import com.android.internal.os.RoSystemProperties;
+import com.android.internal.util.ArrayUtils;
 import com.android.server.SystemConfig;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.List;
+
+import static android.content.pm.PackageManager.GET_PERMISSIONS;
 import static junit.framework.Assert.assertTrue;
 
 
@@ -53,27 +57,34 @@
     }
 
     /**
-     * <p>This test ensures that all signature|privileged permissions are granted to core apps like
-     * systemui/settings. If CONTROL_PRIVAPP_PERMISSIONS is set, the test also verifies that
+     * <p>This test ensures that all signature|privileged permissions are granted to priv-apps.
+     * If CONTROL_PRIVAPP_PERMISSIONS_ENFORCE is set, the test also verifies that
      * granted permissions are whitelisted in {@link SystemConfig}
      */
     @Test
     @SmallTest
     @Presubmit
     public void testPrivAppPermissions() throws PackageManager.NameNotFoundException {
-        String[] testPackages = {"com.android.settings", "com.android.shell",
-                "com.android.systemui"};
-        for (String testPackage : testPackages) {
-            testPackagePrivAppPermission(testPackage);
+        List<PackageInfo> installedPackages = mPackageManager
+                .getInstalledPackages(PackageManager.MATCH_UNINSTALLED_PACKAGES | GET_PERMISSIONS);
+        for (PackageInfo packageInfo : installedPackages) {
+            if (!packageInfo.applicationInfo.isPrivilegedApp()
+                    || PackageManagerService.PLATFORM_PACKAGE_NAME.equals(packageInfo.packageName)) {
+                continue;
+            }
+            testPackagePrivAppPermission(packageInfo);
         }
+
     }
 
-    private void testPackagePrivAppPermission(String testPackage)
+    private void testPackagePrivAppPermission(PackageInfo packageInfo)
             throws PackageManager.NameNotFoundException {
-        PackageInfo packageInfo = mPackageManager.getPackageInfo(testPackage,
-                PackageManager.GET_PERMISSIONS);
+        String packageName = packageInfo.packageName;
         ArraySet<String> privAppPermissions = SystemConfig.getInstance()
-                .getPrivAppPermissions(testPackage);
+                .getPrivAppPermissions(packageName);
+        if (ArrayUtils.isEmpty(packageInfo.requestedPermissions)) {
+            return;
+        }
         for (int i = 0; i < packageInfo.requestedPermissions.length; i++) {
             String pName = packageInfo.requestedPermissions[i];
             int protectionLevel;
@@ -89,13 +100,14 @@
             if ((protectionLevel & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0) {
                 boolean granted = (packageInfo.requestedPermissionsFlags[i]
                         & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0;
-                assertTrue("Permission " + pName + " should be granted to " + testPackage, granted);
-                // if CONTROL_PRIVAPP_PERMISSIONS enabled, platform permissions must be whitelisted
+                assertTrue("Permission " + pName + " should be granted to " + packageName, granted);
+                // if privapp permissions are enforced, platform permissions must be whitelisted
                 // in SystemConfig
-                if (platformPermission && RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS) {
+                if (platformPermission && RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) {
                     assertTrue("Permission " + pName
-                                    + " should be declared in the xml file for package "
-                                    + testPackage,
+                                    + " should be declared in privapp-permissions-platform.xml "
+                                    + "or privapp-permissions-<product>.xml file for package "
+                                    + packageName,
                             privAppPermissions.contains(pName));
                 }
             }
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 771ca146..97bcaf0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -1292,7 +1292,43 @@
                     /* activity =*/ null, /* flags */ 0), getCallingUser());
                 });
 
-        // TODO More tests: pinned but dynamic.
+        // Make sure floating shortcuts don't match with an activity.
+        // At this point, s1 is dynamic and pinned, so it still has a target activity.
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertWith(mLauncherApps.getShortcuts(buildQuery(
+                    /* time =*/ 0,
+                    CALLING_PACKAGE_2,
+                    /* activity =*/ new ComponentName(CALLING_PACKAGE_2,
+                            ShortcutActivity2.class.getName()),
+                    ShortcutQuery.FLAG_GET_PINNED),
+                    getCallingUser()))
+                    .haveIds("s3")
+                    .areAllPinned()
+                    .areAllDynamic()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_2,
+                            ShortcutActivity2.class.getName()));
+        });
+
+        // Now remove as a dynamic, making it floating.
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            mManager.removeDynamicShortcuts(list("s3"));
+            assertWith(mManager.getPinnedShortcuts())
+                    .selectFloating()
+                    .areAllWithNoActivity();
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // This shouldn't match now.
+            assertWith(mLauncherApps.getShortcuts(buildQuery(
+                    /* time =*/ 0,
+                    CALLING_PACKAGE_2,
+                    /* activity =*/ new ComponentName(CALLING_PACKAGE_2,
+                            ShortcutActivity2.class.getName()),
+                    ShortcutQuery.FLAG_GET_PINNED),
+                    getCallingUser()))
+                    .isEmpty();
+        });
+
     }
 
     public void testGetShortcuts_shortcutKinds() throws Exception {
@@ -4921,6 +4957,9 @@
             assertEquals(0, mManager.getDynamicShortcuts().size());
             assertEquals(0, mManager.getPinnedShortcuts().size());
         });
+        assertFalse(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, USER_0)
+                .getPackageInfo().isShadow());
+
 
         installPackage(USER_0, CALLING_PACKAGE_2);
         runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
@@ -4929,6 +4968,8 @@
                     mManager.getPinnedShortcuts()),
                     "s1", "s2", "s3");
         });
+        assertFalse(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, USER_0)
+                .getPackageInfo().isShadow());
 
         installPackage(USER_0, LAUNCHER_1);
         runWithCaller(LAUNCHER_1, USER_0, () -> {
@@ -5052,6 +5093,8 @@
                     mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
                     /* empty */);
         });
+        assertFalse(mService.getLauncherShortcutForTest(LAUNCHER_1, USER_0)
+                .getPackageInfo().isShadow());
 
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
             assertEquals(0, mManager.getDynamicShortcuts().size());
@@ -5074,6 +5117,8 @@
                     mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
                     /* empty */);
         });
+        assertFalse(mService.getLauncherShortcutForTest(LAUNCHER_2, USER_0)
+                .getPackageInfo().isShadow());
 
         installPackage(USER_0, CALLING_PACKAGE_3);
         runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index d25923c..7486858 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -1052,7 +1052,7 @@
 
         assertEquals(CALLING_PACKAGE_1, si.getPackage());
         assertEquals("id", si.getId());
-        assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName());
+        assertNull(si.getActivity()); // It's now floating, so no target activity.
         assertEquals(null, si.getIcon());
         assertEquals("title", si.getTitle());
         assertEquals("text", si.getText());
@@ -1116,7 +1116,7 @@
 
         assertEquals(CALLING_PACKAGE_1, si.getPackage());
         assertEquals("id", si.getId());
-        assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName());
+        assertNull(si.getActivity()); // It's now floating, so no target activity.
         assertEquals(null, si.getIcon());
         assertEquals(10, si.getTitleResId());
         assertEquals("r10", si.getTitleResName());
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceCreateProfileTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceCreateProfileTest.java
new file mode 100644
index 0000000..ad514cf
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceCreateProfileTest.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.app.ApplicationPackageManager;
+import android.content.pm.UserInfo;
+import android.os.Looper;
+import android.os.UserManagerInternal;
+import android.os.UserHandle;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.MediumTest;
+
+import com.android.server.LocalServices;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * <p>Run with:<pre>
+ * runtest -c com.android.server.pm.UserManagerServiceCreateProfileTest frameworks-services
+ * </pre>
+ */
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class UserManagerServiceCreateProfileTest {
+    private UserManagerService mUserManagerService;
+
+    @Before
+    public void setup() {
+        // Currently UserManagerService cannot be instantiated twice inside a VM without a cleanup
+        // TODO: Remove once UMS supports proper dependency injection
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+        LocalServices.removeServiceForTest(UserManagerInternal.class);
+        mUserManagerService = new UserManagerService(InstrumentationRegistry.getContext());
+
+        // The tests assume that the device has one user and its the system user.
+        List<UserInfo> users = mUserManagerService.getUsers(/* excludeDying */ false);
+        assertEquals("Multiple users so this test can't run.", 1, users.size());
+        assertEquals("Only user present isn't the system user.",
+                UserHandle.USER_SYSTEM, users.get(0).id);
+    }
+
+    @Test
+    public void testGetProfiles() {
+        try {
+            // Pretend we have a secondary user with a profile.
+            UserInfo secondaryUser = addUser();
+            UserInfo profile = addProfile(secondaryUser);
+
+            // System user should still have no profile so getProfiles should just return 1 user.
+            List<UserInfo> users =
+                    mUserManagerService.getProfiles(UserHandle.USER_SYSTEM, /*excludeDying*/ false);
+            assertEquals("Profiles returned where none should exist", 1, users.size());
+            assertEquals("Missing system user from profile list of system user",
+                    UserHandle.USER_SYSTEM, users.get(0).id);
+
+            // Secondary user should have 1 profile, so return that and itself.
+            users = mUserManagerService.getProfiles(secondaryUser.id, /*excludeDying*/ false);
+            assertEquals("Profiles returned where none should exist", 2, users.size());
+            assertTrue("Missing secondary user id", users.get(0).id == secondaryUser.id
+                    || users.get(1).id == secondaryUser.id);
+            assertTrue("Missing profile user id", users.get(0).id == profile.id
+                    || users.get(1).id == profile.id);
+        } finally {
+            removeUsers();
+        }
+    }
+
+    @Test
+    public void testProfileBadge() {
+        try {
+            // First profile for system user should get badge 0
+            assertEquals("First profile isn't given badge index 0", 0,
+                    mUserManagerService.getFreeProfileBadgeLU(UserHandle.USER_SYSTEM));
+
+            // Pretend we have a secondary user.
+            UserInfo secondaryUser = addUser();
+
+            // Check first profile badge for secondary user is also 0.
+            assertEquals("First profile for secondary user isn't given badge index 0", 0,
+                    mUserManagerService.getFreeProfileBadgeLU(secondaryUser.id));
+
+            // Shouldn't impact the badge for profile in system user
+            assertEquals("First profile isn't given badge index 0 with secondary user", 0,
+                    mUserManagerService.getFreeProfileBadgeLU(UserHandle.USER_SYSTEM));
+
+            // Pretend a secondary user has a profile.
+            addProfile(secondaryUser);
+
+            // Shouldn't have impacted the badge for the system user
+            assertEquals("First profile isn't given badge index 0 in secondary user", 0,
+                    mUserManagerService.getFreeProfileBadgeLU(UserHandle.USER_SYSTEM));
+        } finally {
+            removeUsers();
+        }
+    }
+
+    @Test
+    public void testProfileBadgeUnique() {
+        try {
+            List<UserInfo> users = mUserManagerService.getUsers(/* excludeDying */ false);
+            UserInfo system = users.get(0);
+            // Badges should get allocated 0 -> max
+            for (int i = 0; i < UserManagerService.getMaxManagedProfiles(); ++i) {
+                int nextBadge = mUserManagerService.getFreeProfileBadgeLU(UserHandle.USER_SYSTEM);
+                assertEquals("Wrong badge allocated", i, nextBadge);
+                UserInfo profile = addProfile(system);
+                profile.profileBadge = nextBadge;
+            }
+        } finally {
+            removeUsers();
+        }
+    }
+
+    @Test
+    public void testProfileBadgeReuse() {
+        try {
+            // Pretend we have a secondary user with a profile.
+            UserInfo secondaryUser = addUser();
+            UserInfo profile = addProfile(secondaryUser);
+            // Add the profile it to the users being removed.
+            mUserManagerService.addRemovingUserIdLocked(profile.id);
+            // We should reuse the badge from the profile being removed.
+            assertEquals("Badge index not reused while removing a user", 0,
+                    mUserManagerService.getFreeProfileBadgeLU(secondaryUser.id));
+
+            // Edge case of reuse that only applies if we ever support 3 managed profiles
+            // We should prioritise using lower badge indexes
+            if (UserManagerService.getMaxManagedProfiles() > 2) {
+                UserInfo profileBadgeOne = addProfile(secondaryUser);
+                profileBadgeOne.profileBadge = 1;
+                // 0 and 2 are free, we should reuse 0 rather than 2.
+                assertEquals("Lower index not used", 0,
+                        mUserManagerService.getFreeProfileBadgeLU(secondaryUser.id));
+            }
+        } finally {
+            removeUsers();
+        }
+    }
+
+    @Test
+    public void testNumberOfBadges() {
+        assertTrue("Max profiles greater than number of badges",
+                UserManagerService.MAX_MANAGED_PROFILES
+                <= ApplicationPackageManager.CORP_BADGE_COLORS.length);
+        assertEquals("Num colors doesn't match number of badge labels",
+                ApplicationPackageManager.CORP_BADGE_COLORS.length,
+                ApplicationPackageManager.CORP_BADGE_LABEL_RES_ID.length);
+    }
+
+    private void removeUsers() {
+        List<UserInfo> users = mUserManagerService.getUsers(/* excludeDying */ false);
+        for (UserInfo user: users) {
+            if (user.id != UserHandle.USER_SYSTEM) {
+                mUserManagerService.removeUserInfo(user.id);
+            }
+        }
+    }
+
+    private UserInfo addProfile(UserInfo user) {
+        user.profileGroupId = user.id;
+        UserInfo profile = new UserInfo(
+                mUserManagerService.getNextAvailableId(), "profile",
+                UserInfo.FLAG_MANAGED_PROFILE);
+        profile.profileGroupId = user.id;
+        mUserManagerService.putUserInfo(profile);
+        return profile;
+    }
+
+    private UserInfo addUser() {
+        UserInfo secondaryUser = new UserInfo(
+                mUserManagerService.getNextAvailableId(), "secondary", /* flags */ 0);
+        mUserManagerService.putUserInfo(secondaryUser);
+        return secondaryUser;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
new file mode 100644
index 0000000..575d7a3
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.pm;
+
+import android.content.pm.UserInfo;
+import android.os.Looper;
+import android.os.Parcel;
+import android.os.UserManagerInternal;
+import android.os.UserHandle;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.MediumTest;
+
+import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerService.UserData;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * <p>Run with:<pre>
+ * runtest -c com.android.server.pm.UserManagerServiceUserInfoTest frameworks-services
+ * </pre>
+ */
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class UserManagerServiceUserInfoTest {
+    private UserManagerService mUserManagerService;
+
+    @Before
+    public void setup() {
+        // Currently UserManagerService cannot be instantiated twice inside a VM without a cleanup
+        // TODO: Remove once UMS supports proper dependency injection
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+        LocalServices.removeServiceForTest(UserManagerInternal.class);
+        mUserManagerService = new UserManagerService(InstrumentationRegistry.getContext());
+
+        // The tests assume that the device has one user and its the system user.
+        List<UserInfo> users = mUserManagerService.getUsers(/* excludeDying */ false);
+        assertEquals("Multiple users so this test can't run.", 1, users.size());
+        assertEquals("Only user present isn't the system user.",
+                UserHandle.USER_SYSTEM, users.get(0).id);
+    }
+
+    @Test
+    public void testWriteReadUserInfo() throws Exception {
+        UserData data = new UserData();
+        data.info = createUser();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        DataOutputStream out = new DataOutputStream(baos);
+        mUserManagerService.writeUserLP(data, out);
+        byte[] bytes = baos.toByteArray();
+
+        UserData read = mUserManagerService.readUserLP(
+                data.info.id, new ByteArrayInputStream(bytes));
+
+        assertUserInfoEquals(data.info, read.info);
+    }
+
+    @Test
+    public void testParcelUnparcelUserInfo() throws Exception {
+        UserInfo info = createUser();
+
+        Parcel out = Parcel.obtain();
+        info.writeToParcel(out, 0);
+        byte[] data = out.marshall();
+        out.recycle();
+
+        Parcel in = Parcel.obtain();
+        in.unmarshall(data, 0, data.length);
+        in.setDataPosition(0);
+        UserInfo read = UserInfo.CREATOR.createFromParcel(in);
+        in.recycle();
+
+        assertUserInfoEquals(info, read);
+    }
+
+    private UserInfo createUser() {
+        UserInfo user = new UserInfo(/*id*/ 21, "A Name", "A path", /*flags*/ 0x0ff0ff);
+        user.serialNumber = 5;
+        user.creationTime = 4L << 32;
+        user.lastLoggedInTime = 5L << 32;
+        user.lastLoggedInFingerprint = "afingerprint";
+        user.profileGroupId = 45;
+        user.restrictedProfileParentId = 4;
+        user.profileBadge = 2;
+        user.partial = true;
+        user.guestToRemove = true;
+        return user;
+    }
+
+    private void assertUserInfoEquals(UserInfo one, UserInfo two) {
+        assertEquals("Id not preserved", one.id, two.id);
+        assertEquals("Name not preserved", one.name, two.name);
+        assertEquals("Icon path not preserved", one.iconPath, two.iconPath);
+        assertEquals("Flags not preserved", one.flags, two.flags);
+        assertEquals("profile group not preserved", one.profileGroupId,
+                two.profileGroupId);
+        assertEquals("restricted profile parent not preseved", one.restrictedProfileParentId,
+                two.restrictedProfileParentId);
+        assertEquals("profile badge not preseved", one.profileBadge, two.profileBadge);
+        assertEquals("partial not preseved", one.partial, two.partial);
+        assertEquals("guestToRemove not preseved", one.guestToRemove, two.guestToRemove);
+    }
+}
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 0801a88..162a1a9 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -25,14 +25,7 @@
 
 import java.util.ArrayList;
 
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static org.junit.Assert.assertEquals;
 
 /**
@@ -48,21 +41,8 @@
 
     @Test
     public void testForAllWindows() throws Exception {
-        final DisplayContent dc = new DisplayContent(mDisplay, sWm, null, null);
-        final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, dc, "wallpaper");
-        final WindowState imeWindow = createWindow(null, TYPE_INPUT_METHOD, dc, "ime");
-        final WindowState imeDialogWindow = createWindow(null, TYPE_INPUT_METHOD_DIALOG, dc,
-                "ime dialog");
-        final WindowState statusBarWindow = createWindow(null, TYPE_STATUS_BAR, dc, "status bar");
-        final WindowState navBarWindow = createWindow(null, TYPE_NAVIGATION_BAR,
-                statusBarWindow.mToken, "nav bar");
-        final WindowState appWindow = createWindow(null, TYPE_BASE_APPLICATION, dc, "app");
-        final WindowState negChildAppWindow = createWindow(appWindow, TYPE_APPLICATION_MEDIA,
-                appWindow.mToken, "negative app child");
-        final WindowState posChildAppWindow = createWindow(appWindow,
-                TYPE_APPLICATION_ATTACHED_DIALOG, appWindow.mToken, "positive app child");
-        final WindowState exitingAppWindow = createWindow(null, TYPE_BASE_APPLICATION, dc,
-                "exiting app");
+        final WindowState exitingAppWindow = createWindow(null, TYPE_BASE_APPLICATION,
+                sDisplayContent, "exiting app");
         final AppWindowToken exitingAppToken = exitingAppWindow.mAppToken;
         exitingAppToken.mIsExiting = true;
         exitingAppToken.mTask.mStack.mExitingAppTokens.add(exitingAppToken);
@@ -70,30 +50,75 @@
         final ArrayList<WindowState> windows = new ArrayList();
 
         // Test forward traversal.
-        dc.forAllWindows(w -> {windows.add(w);}, false /* traverseTopToBottom */);
+        sDisplayContent.forAllWindows(w -> {windows.add(w);}, false /* traverseTopToBottom */);
 
-        assertEquals(wallpaperWindow, windows.get(0));
+        assertEquals(sWallpaperWindow, windows.get(0));
         assertEquals(exitingAppWindow, windows.get(1));
-        assertEquals(negChildAppWindow, windows.get(2));
-        assertEquals(appWindow, windows.get(3));
-        assertEquals(posChildAppWindow, windows.get(4));
-        assertEquals(statusBarWindow, windows.get(5));
-        assertEquals(navBarWindow, windows.get(6));
-        assertEquals(imeWindow, windows.get(7));
-        assertEquals(imeDialogWindow, windows.get(8));
+        assertEquals(sChildAppWindowBelow, windows.get(2));
+        assertEquals(sAppWindow, windows.get(3));
+        assertEquals(sChildAppWindowAbove, windows.get(4));
+        assertEquals(sDockedDividerWindow, 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();
-        dc.forAllWindows(w -> {windows.add(w);}, true /* traverseTopToBottom */);
+        sDisplayContent.forAllWindows(w -> {windows.add(w);}, true /* traverseTopToBottom */);
 
-        assertEquals(wallpaperWindow, windows.get(8));
-        assertEquals(exitingAppWindow, windows.get(7));
-        assertEquals(negChildAppWindow, windows.get(6));
-        assertEquals(appWindow, windows.get(5));
-        assertEquals(posChildAppWindow, windows.get(4));
-        assertEquals(statusBarWindow, windows.get(3));
-        assertEquals(navBarWindow, windows.get(2));
-        assertEquals(imeWindow, windows.get(1));
-        assertEquals(imeDialogWindow, windows.get(0));
+        assertEquals(sWallpaperWindow, windows.get(9));
+        assertEquals(exitingAppWindow, 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(sNavBarWindow, windows.get(2));
+        assertEquals(sImeWindow, windows.get(1));
+        assertEquals(sImeDialogWindow, windows.get(0));
+    }
+
+    @Test
+    public void testForAllWindows_WithImeTarget() throws Exception {
+        final WindowState imeAppTarget =
+                createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "imeAppTarget");
+
+        sWm.mInputMethodTarget = imeAppTarget;
+
+        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(imeAppTarget, windows.get(4));
+        assertEquals(sImeWindow, windows.get(5));
+        assertEquals(sImeDialogWindow, windows.get(6));
+        assertEquals(sDockedDividerWindow, windows.get(7));
+        assertEquals(sStatusBarWindow, windows.get(8));
+        assertEquals(sNavBarWindow, 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(imeAppTarget, windows.get(5));
+        assertEquals(sImeWindow, windows.get(4));
+        assertEquals(sImeDialogWindow, windows.get(3));
+        assertEquals(sDockedDividerWindow, windows.get(2));
+        assertEquals(sStatusBarWindow, windows.get(1));
+        assertEquals(sNavBarWindow, windows.get(0));
+
+        // Clean-up
+        sWm.mInputMethodTarget = null;
+        imeAppTarget.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 fd1c91a..b10c273 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
@@ -27,6 +27,7 @@
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.view.DisplayInfo;
 import android.view.Gravity;
 import android.view.IWindow;
 import android.view.WindowManager;
@@ -53,6 +54,7 @@
 
     class WindowStateWithTask extends WindowState {
         final Task mTask;
+        boolean mDockedResizingForTest = false;
         WindowStateWithTask(WindowManager.LayoutParams attrs, Task t) {
             super(sWm, null, mIWindow, mWindowToken, null, 0, 0, attrs, 0, 0);
             mTask = t;
@@ -62,6 +64,11 @@
         Task getTask() {
             return mTask;
         }
+
+        @Override
+        boolean isDockedResizing() {
+            return mDockedResizingForTest;
+        }
     };
 
     class TaskWithBounds extends Task {
@@ -92,6 +99,10 @@
     public void setUp() throws Exception {
         final Context context = InstrumentationRegistry.getTargetContext();
         sWm = TestWindowManagerPolicy.getWindowManagerService(context);
+
+        // Just any non zero value.
+        sWm.mSystemDecorLayer = 10000;
+
         mWindowToken = new WindowToken(sWm, new Binder(), 0, false,
                 sWm.getDefaultDisplayContentLocked());
         mStubStack = new TaskStack(sWm, 0);
@@ -274,7 +285,63 @@
         assertRect(w.mContentInsets, 0, 0, 100, 100);
     }
 
-    private WindowState createWindow(Task task, int width, int height) {
+    @Test
+    public void testCalculatePolicyCrop() {
+        final WindowStateWithTask w = createWindow(
+                new TaskWithBounds(null), FILL_PARENT, FILL_PARENT);
+        w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
+
+        final Rect pf = new Rect(0, 0, 1000, 1000);
+        final Rect df = pf;
+        final Rect of = df;
+        final Rect cf = new Rect(pf);
+        // Produce some insets
+        cf.top += 50;
+        cf.bottom -= 100;
+        final Rect vf = cf;
+        final Rect sf = vf;
+        // We use a decor content frame with insets to produce cropping.
+        Rect dcf = cf;
+
+        final Rect policyCrop = new Rect();
+
+        w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null);
+        w.calculatePolicyCrop(policyCrop);
+        // If we were above system decor we wouldnt' get any cropping though
+        w.mLayer = sWm.mSystemDecorLayer + 1;
+        w.calculatePolicyCrop(policyCrop);
+        assertRect(policyCrop, 0, 0, 1000, 1000);
+        w.mLayer = 1;
+        dcf.setEmpty();
+        // Likewise with no decor frame we would get no crop
+        w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null);
+        w.calculatePolicyCrop(policyCrop);
+        assertRect(policyCrop, 0, 0, 1000, 1000);
+
+        // Now we set up a window which doesn't fill the entire decor frame.
+        // Normally it would be cropped to it's frame but in the case of docked resizing
+        // we need to account for the fact the windows surface will be made
+        // fullscreen and thus also make the crop fullscreen.
+        w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
+        w.mAttrs.width = 500;
+        w.mAttrs.height = 500;
+        w.mRequestedWidth = 500;
+        w.mRequestedHeight = 500;
+        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
+
+        w.calculatePolicyCrop(policyCrop);
+        // Normally the crop is shrunk from the decor frame
+        // to the computed window frame.
+        assertRect(policyCrop, 0, 0, 500, 500);
+
+        w.mDockedResizingForTest = true;
+        w.calculatePolicyCrop(policyCrop);
+        // But if we are docked resizing it won't be.
+        final DisplayInfo displayInfo = w.getDisplayContent().getDisplayInfo();
+        assertRect(policyCrop, 0, 0, 1000, 1000);
+    }
+
+    private WindowStateWithTask createWindow(Task task, int width, int height) {
         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
         attrs.width = width;
         attrs.height = height;
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java
index 5a035d6..c8650bf 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -25,14 +24,9 @@
 import android.support.test.runner.AndroidJUnit4;
 
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 
 /**
  * Tests for the {@link WindowLayersController} class.
@@ -45,43 +39,6 @@
 @RunWith(AndroidJUnit4.class)
 public class WindowLayersControllerTests extends WindowTestsBase {
 
-    private static boolean sOneTimeSetupDone = false;
-    private static WindowLayersController sLayersController;
-    private static DisplayContent sDisplayContent;
-    private static WindowState sImeWindow;
-    private static WindowState sImeDialogWindow;
-    private static WindowState sStatusBarWindow;
-    private static WindowState sDockedDividerWindow;
-    private static WindowState sNavBarWindow;
-    private static WindowState sAppWindow;
-    private static WindowState sChildAppWindow;
-
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-
-        if (sOneTimeSetupDone) {
-            return;
-        }
-        sOneTimeSetupDone = true;
-        sLayersController = new WindowLayersController(sWm);
-        sDisplayContent =
-                new DisplayContent(mDisplay, sWm, sLayersController, new WallpaperController(sWm));
-        final WindowState wallpaperWindow =
-                createWindow(null, TYPE_WALLPAPER, sDisplayContent, "wallpaperWindow");
-        sImeWindow = createWindow(null, TYPE_INPUT_METHOD, sDisplayContent, "sImeWindow");
-        sImeDialogWindow =
-                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");
-        sDockedDividerWindow =
-                createWindow(null, TYPE_DOCK_DIVIDER, sDisplayContent, "sDockedDividerWindow");
-        sAppWindow = createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "sAppWindow");
-        sChildAppWindow = createWindow(sAppWindow,
-                TYPE_APPLICATION_ATTACHED_DIALOG, sAppWindow.mToken, "sChildAppWindow");
-    }
-
     @Test
     public void testAssignWindowLayers_ForImeWithNoTarget() throws Exception {
         sWm.mInputMethodTarget = null;
@@ -90,7 +47,7 @@
         // The Ime has an higher base layer than app windows and lower base layer than system
         // windows, so it should be above app windows and below system windows if there isn't an IME
         // target.
-        assertWindowLayerGreaterThan(sImeWindow, sChildAppWindow);
+        assertWindowLayerGreaterThan(sImeWindow, sChildAppWindowAbove);
         assertWindowLayerGreaterThan(sImeWindow, sAppWindow);
         assertWindowLayerGreaterThan(sImeWindow, sDockedDividerWindow);
         assertWindowLayerGreaterThan(sNavBarWindow, sImeWindow);
@@ -110,7 +67,63 @@
         // Ime should be above all app windows and below system windows if it is targeting an app
         // window.
         assertWindowLayerGreaterThan(sImeWindow, imeAppTarget);
-        assertWindowLayerGreaterThan(sImeWindow, sChildAppWindow);
+        assertWindowLayerGreaterThan(sImeWindow, sChildAppWindowAbove);
+        assertWindowLayerGreaterThan(sImeWindow, sAppWindow);
+        assertWindowLayerGreaterThan(sImeWindow, sDockedDividerWindow);
+        assertWindowLayerGreaterThan(sNavBarWindow, sImeWindow);
+        assertWindowLayerGreaterThan(sStatusBarWindow, sImeWindow);
+
+        // And, IME dialogs should always have an higher layer than the IME.
+        assertWindowLayerGreaterThan(sImeDialogWindow, sImeWindow);
+    }
+
+    @Test
+    public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() throws Exception {
+        final WindowState imeAppTarget =
+                createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "imeAppTarget");
+        final WindowState imeAppTargetChildAboveWindow = createWindow(imeAppTarget,
+                TYPE_APPLICATION_ATTACHED_DIALOG, imeAppTarget.mToken,
+                "imeAppTargetChildAboveWindow");
+        final WindowState imeAppTargetChildBelowWindow = createWindow(imeAppTarget,
+                TYPE_APPLICATION_MEDIA_OVERLAY, imeAppTarget.mToken,
+                "imeAppTargetChildBelowWindow");
+
+        sWm.mInputMethodTarget = imeAppTarget;
+        sLayersController.assignWindowLayers(sDisplayContent);
+
+        // Ime should be above all app windows except for child windows that are z-ordered above it
+        // and below system windows if it is targeting an app window.
+        assertWindowLayerGreaterThan(sImeWindow, imeAppTarget);
+        assertWindowLayerGreaterThan(imeAppTargetChildAboveWindow, sImeWindow);
+        assertWindowLayerGreaterThan(sImeWindow, imeAppTargetChildBelowWindow);
+        assertWindowLayerGreaterThan(sImeWindow, sChildAppWindowAbove);
+        assertWindowLayerGreaterThan(sImeWindow, sAppWindow);
+        assertWindowLayerGreaterThan(sImeWindow, sDockedDividerWindow);
+        assertWindowLayerGreaterThan(sNavBarWindow, sImeWindow);
+        assertWindowLayerGreaterThan(sStatusBarWindow, sImeWindow);
+
+        // And, IME dialogs should always have an higher layer than the IME.
+        assertWindowLayerGreaterThan(sImeDialogWindow, sImeWindow);
+    }
+
+    @Test
+    public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() throws Exception {
+        final WindowState appBelowImeTarget =
+                createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "appBelowImeTarget");
+        final WindowState imeAppTarget =
+                createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "imeAppTarget");
+        final WindowState appAboveImeTarget =
+                createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "appAboveImeTarget");
+
+        sWm.mInputMethodTarget = imeAppTarget;
+        sLayersController.assignWindowLayers(sDisplayContent);
+
+        // Ime should be above all app windows except for non-fullscreen app window above it and
+        // below system windows if it is targeting an app window.
+        assertWindowLayerGreaterThan(sImeWindow, imeAppTarget);
+        assertWindowLayerGreaterThan(sImeWindow, appBelowImeTarget);
+        assertWindowLayerGreaterThan(appAboveImeTarget, sImeWindow);
+        assertWindowLayerGreaterThan(sImeWindow, sChildAppWindowAbove);
         assertWindowLayerGreaterThan(sImeWindow, sAppWindow);
         assertWindowLayerGreaterThan(sImeWindow, sDockedDividerWindow);
         assertWindowLayerGreaterThan(sNavBarWindow, sImeWindow);
@@ -131,7 +144,7 @@
         // The IME target base layer is higher than all window except for the nav bar window, so the
         // IME should be above all windows except for the nav bar.
         assertWindowLayerGreaterThan(sImeWindow, imeSystemOverlayTarget);
-        assertWindowLayerGreaterThan(sImeWindow, sChildAppWindow);
+        assertWindowLayerGreaterThan(sImeWindow, sChildAppWindowAbove);
         assertWindowLayerGreaterThan(sImeWindow, sAppWindow);
         assertWindowLayerGreaterThan(sImeWindow, sDockedDividerWindow);
         assertWindowLayerGreaterThan(sImeWindow, sStatusBarWindow);
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 9681bd2..e301b19 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -22,7 +22,6 @@
 import android.content.Context;
 import android.os.IBinder;
 import android.support.test.InstrumentationRegistry;
-import android.view.Display;
 import android.view.IWindow;
 import android.view.WindowManager;
 
@@ -31,6 +30,15 @@
 import static android.content.res.Configuration.EMPTY;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static org.mockito.Mockito.mock;
 
 /**
@@ -40,15 +48,49 @@
     static WindowManagerService sWm = null;
     private final IWindow mIWindow = new TestIWindow();
     private final Session mMockSession = mock(Session.class);
-    Display mDisplay;
     private static int sNextStackId = FIRST_DYNAMIC_STACK_ID;
     private static int sNextTaskId = 0;
 
+    private static boolean sOneTimeSetupDone = false;
+    protected static DisplayContent sDisplayContent;
+    protected static WindowLayersController sLayersController;
+    protected static WindowState sWallpaperWindow;
+    protected static WindowState sImeWindow;
+    protected static WindowState sImeDialogWindow;
+    protected static WindowState sStatusBarWindow;
+    protected static WindowState sDockedDividerWindow;
+    protected static WindowState sNavBarWindow;
+    protected static WindowState sAppWindow;
+    protected static WindowState sChildAppWindowAbove;
+    protected static WindowState sChildAppWindowBelow;
+
     @Before
     public void setUp() throws Exception {
+        if (sOneTimeSetupDone) {
+            return;
+        }
+        sOneTimeSetupDone = true;
         final Context context = InstrumentationRegistry.getTargetContext();
         sWm = TestWindowManagerPolicy.getWindowManagerService(context);
-        mDisplay = context.getDisplay();
+        sLayersController = new WindowLayersController(sWm);
+        sDisplayContent = new DisplayContent(context.getDisplay(), sWm, sLayersController,
+                new WallpaperController(sWm));
+
+        // Set-up some common windows.
+        sWallpaperWindow = createWindow(null, TYPE_WALLPAPER, sDisplayContent, "wallpaperWindow");
+        sImeWindow = createWindow(null, TYPE_INPUT_METHOD, sDisplayContent, "sImeWindow");
+        sImeDialogWindow =
+                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");
+        sDockedDividerWindow =
+                createWindow(null, TYPE_DOCK_DIVIDER, sDisplayContent, "sDockedDividerWindow");
+        sAppWindow = createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "sAppWindow");
+        sChildAppWindowAbove = createWindow(sAppWindow,
+                TYPE_APPLICATION_ATTACHED_DIALOG, sAppWindow.mToken, "sChildAppWindowAbove");
+        sChildAppWindowBelow = createWindow(sAppWindow,
+                TYPE_APPLICATION_MEDIA_OVERLAY, sAppWindow.mToken, "sChildAppWindowBelow");
     }
 
     /** Asserts that the first entry is greater than the second entry. */
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 1fe5cb7..6e74deb 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
@@ -764,6 +764,12 @@
                     filter(mList, ShortcutInfo::isPinned));
         }
 
+        public ShortcutListAsserter selectFloating() {
+            return new ShortcutListAsserter(this,
+                    filter(mList, (si -> si.isPinned()
+                            && !(si.isDynamic() || si.isDeclaredInManifest()))));
+        }
+
         public ShortcutListAsserter selectByActivity(ComponentName activity) {
             return new ShortcutListAsserter(this,
                     ShortcutManagerTestUtils.filterByActivity(mList, activity));
@@ -895,6 +901,11 @@
             return this;
         }
 
+        public ShortcutListAsserter areAllWithNoActivity() {
+            forAllShortcuts(s -> assertNull("id=" + s.getId(), s.getActivity()));
+            return this;
+        }
+
         public ShortcutListAsserter forAllShortcuts(Consumer<ShortcutInfo> sa) {
             boolean found = false;
             for (int i = 0; i < mList.size(); i++) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 7217c3b..515370f 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -791,7 +791,7 @@
     int getAppId(String packageName) {
         try {
             ApplicationInfo ai = mPackageManager.getApplicationInfo(packageName,
-                    PackageManager.MATCH_UNINSTALLED_PACKAGES
+                    PackageManager.MATCH_ANY_USER
                             | PackageManager.MATCH_DISABLED_COMPONENTS);
             return ai.uid;
         } catch (NameNotFoundException re) {
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 0544fae..b86a85b 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -119,6 +119,7 @@
     private static final int MSG_USER_SWITCHED = 5;
     private static final int MSG_UPDATE_USER_RESTRICTIONS = 6;
     private static final int MSG_UPDATE_HOST_STATE = 7;
+    private static final int MSG_ACCESSORY_MODE_ENTER_TIMEOUT = 8;
 
     private static final int AUDIO_MODE_SOURCE = 1;
 
@@ -127,9 +128,6 @@
     // which need debouncing.
     private static final int UPDATE_DELAY = 1000;
 
-    // Time we received a request to enter USB accessory mode
-    private long mAccessoryModeRequestTime = 0;
-
     // Timeout for entering USB request mode.
     // Request is cancelled if host does not configure device within 10 seconds.
     private static final int ACCESSORY_REQUEST_TIMEOUT = 10 * 1000;
@@ -297,7 +295,8 @@
         }
 
         if (functions != null) {
-            mAccessoryModeRequestTime = SystemClock.elapsedRealtime();
+            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_ACCESSORY_MODE_ENTER_TIMEOUT),
+                    ACCESSORY_REQUEST_TIMEOUT);
             setCurrentFunctions(functions, false);
         }
     }
@@ -586,14 +585,10 @@
         private void updateCurrentAccessory() {
             // We are entering accessory mode if we have received a request from the host
             // and the request has not timed out yet.
-            boolean enteringAccessoryMode =
-                    mAccessoryModeRequestTime > 0 &&
-                        SystemClock.elapsedRealtime() <
-                            mAccessoryModeRequestTime + ACCESSORY_REQUEST_TIMEOUT;
+            boolean enteringAccessoryMode = hasMessages(MSG_ACCESSORY_MODE_ENTER_TIMEOUT);
 
             if (mConfigured && enteringAccessoryMode) {
                 // successfully entered accessory mode
-
                 if (mAccessoryStrings != null) {
                     mCurrentAccessory = new UsbAccessory(mAccessoryStrings);
                     Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
@@ -604,19 +599,23 @@
                 } else {
                     Slog.e(TAG, "nativeGetAccessoryStrings failed");
                 }
-            } else if (!enteringAccessoryMode) {
-                // make sure accessory mode is off
-                // and restore default functions
-                Slog.d(TAG, "exited USB accessory mode");
-                setEnabledFunctions(null, false, false);
+            } else if (!mConnected && !enteringAccessoryMode) {
+                notifyAccessoryModeExit();
+            }
+        }
 
-                if (mCurrentAccessory != null) {
-                    if (mBootCompleted) {
-                        mSettingsManager.usbAccessoryRemoved(mCurrentAccessory);
-                    }
-                    mCurrentAccessory = null;
-                    mAccessoryStrings = null;
+        private void notifyAccessoryModeExit() {
+            // make sure accessory mode is off
+            // and restore default functions
+            Slog.d(TAG, "exited USB accessory mode");
+            setEnabledFunctions(null, false, false);
+
+            if (mCurrentAccessory != null) {
+                if (mBootCompleted) {
+                    mSettingsManager.usbAccessoryRemoved(mCurrentAccessory);
                 }
+                mCurrentAccessory = null;
+                mAccessoryStrings = null;
             }
         }
 
@@ -805,6 +804,12 @@
                     }
                     break;
                 }
+                case MSG_ACCESSORY_MODE_ENTER_TIMEOUT: {
+                    if (!mConnected) {
+                        notifyAccessoryModeExit();
+                    }
+                    break;
+                }
             }
         }
 
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index c99e22a..c69b7c2 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -324,6 +324,7 @@
         private final PhoneAccountHandle mAccountHandle;
         private final int mCallCapabilities;
         private final int mCallProperties;
+        private final int mSupportedAudioRoutes = CallAudioState.ROUTE_ALL;
         private final DisconnectCause mDisconnectCause;
         private final long mConnectTimeMillis;
         private final GatewayInfo mGatewayInfo;
@@ -536,6 +537,15 @@
         }
 
         /**
+         * @return a bitmask of the audio routes available for the call.
+         *
+         * @hide
+         */
+        public int getSupportedAudioRoutes() {
+            return mSupportedAudioRoutes;
+        }
+
+        /**
          * @return For a {@link #STATE_DISCONNECTED} {@code Call}, the disconnect cause expressed
          * by {@link android.telecom.DisconnectCause}.
          */
diff --git a/telecomm/java/android/telecom/CallAudioState.java b/telecomm/java/android/telecom/CallAudioState.java
index 2b16722..f601d8b 100644
--- a/telecomm/java/android/telecom/CallAudioState.java
+++ b/telecomm/java/android/telecom/CallAudioState.java
@@ -44,8 +44,12 @@
      */
     public static final int ROUTE_WIRED_OR_EARPIECE = ROUTE_EARPIECE | ROUTE_WIRED_HEADSET;
 
-    /** Bit mask of all possible audio routes. */
-    private static final int ROUTE_ALL = ROUTE_EARPIECE | ROUTE_BLUETOOTH | ROUTE_WIRED_HEADSET |
+    /**
+     * Bit mask of all possible audio routes.
+     *
+     * @hide
+     **/
+    public static final int ROUTE_ALL = ROUTE_EARPIECE | ROUTE_BLUETOOTH | ROUTE_WIRED_HEADSET |
             ROUTE_SPEAKER;
 
     private final boolean isMuted;
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 2b9a508..7d258a0 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -723,6 +723,7 @@
         public void onDestroyed(Connection c) {}
         public void onConnectionCapabilitiesChanged(Connection c, int capabilities) {}
         public void onConnectionPropertiesChanged(Connection c, int properties) {}
+        public void onSupportedAudioRoutesChanged(Connection c, int supportedAudioRoutes) {}
         public void onVideoProviderChanged(
                 Connection c, VideoProvider videoProvider) {}
         public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {}
@@ -1485,6 +1486,7 @@
     private boolean mRingbackRequested = false;
     private int mConnectionCapabilities;
     private int mConnectionProperties;
+    private int mSupportedAudioRoutes = CallAudioState.ROUTE_ALL;
     private VideoProvider mVideoProvider;
     private boolean mAudioModeIsVoip;
     private long mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED;
@@ -1765,6 +1767,15 @@
     }
 
     /**
+     * Returns the connection's supported audio routes.
+     *
+     * @hide
+     */
+    public final int getSupportedAudioRoutes() {
+        return mSupportedAudioRoutes;
+    }
+
+    /**
      * Sets the value of the {@link #getAddress()} property.
      *
      * @param address The new address.
@@ -1986,6 +1997,28 @@
     }
 
     /**
+     * Sets the supported audio routes.
+     *
+     * @param supportedAudioRoutes the supported audio routes as a bitmask.
+     *                             See {@link CallAudioState}
+     * @hide
+     */
+    public final void setSupportedAudioRoutes(int supportedAudioRoutes) {
+        if ((supportedAudioRoutes
+                & (CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER)) == 0) {
+            throw new IllegalArgumentException(
+                    "supported audio routes must include either speaker or earpiece");
+        }
+
+        if (mSupportedAudioRoutes != supportedAudioRoutes) {
+            mSupportedAudioRoutes = supportedAudioRoutes;
+            for (Listener l : mListeners) {
+                l.onSupportedAudioRoutesChanged(this, mSupportedAudioRoutes);
+            }
+        }
+    }
+
+    /**
      * Tears down the Connection object.
      */
     public final void destroy() {
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index c2a0ff1..b119e16 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -1131,6 +1131,7 @@
                         connection.getState(),
                         connection.getConnectionCapabilities(),
                         connection.getConnectionProperties(),
+                        connection.getSupportedAudioRoutes(),
                         connection.getAddress(),
                         connection.getAddressPresentation(),
                         connection.getCallerDisplayName(),
@@ -1530,6 +1531,7 @@
                     connection.getState(),
                     connection.getConnectionCapabilities(),
                     connection.getConnectionProperties(),
+                    connection.getSupportedAudioRoutes(),
                     connection.getAddress(),
                     connection.getAddressPresentation(),
                     connection.getCallerDisplayName(),
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index 1900cb9..a3fce9c 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -39,6 +39,7 @@
     private final List<String> mCannedSmsResponses;
     private final int mCapabilities;
     private final int mProperties;
+    private final int mSupportedAudioRoutes;
     private final long mConnectTimeMillis;
     private final Uri mHandle;
     private final int mHandlePresentation;
@@ -64,6 +65,7 @@
             List<String> cannedSmsResponses,
             int capabilities,
             int properties,
+            int supportedAudioRoutes,
             long connectTimeMillis,
             Uri handle,
             int handlePresentation,
@@ -86,6 +88,7 @@
         mCannedSmsResponses = cannedSmsResponses;
         mCapabilities = capabilities;
         mProperties = properties;
+        mSupportedAudioRoutes = supportedAudioRoutes;
         mConnectTimeMillis = connectTimeMillis;
         mHandle = handle;
         mHandlePresentation = handlePresentation;
@@ -137,6 +140,11 @@
     /** Bitmask of properties of the call. */
     public int getProperties() { return mProperties; }
 
+    /** Bitmask of supported routes of the call */
+    public int getSupportedAudioRoutes() {
+        return mSupportedAudioRoutes;
+    }
+
     /** The time that the call switched to the active state. */
     public long getConnectTimeMillis() {
         return mConnectTimeMillis;
@@ -292,6 +300,7 @@
             source.readList(conferenceableCallIds, classLoader);
             Bundle intentExtras = source.readBundle(classLoader);
             Bundle extras = source.readBundle(classLoader);
+            int supportedAudioRoutes = source.readInt();
             return new ParcelableCall(
                     id,
                     state,
@@ -299,6 +308,7 @@
                     cannedSmsResponses,
                     capabilities,
                     properties,
+                    supportedAudioRoutes,
                     connectTimeMillis,
                     handle,
                     handlePresentation,
@@ -355,6 +365,7 @@
         destination.writeList(mConferenceableCallIds);
         destination.writeBundle(mIntentExtras);
         destination.writeBundle(mExtras);
+        destination.writeInt(mSupportedAudioRoutes);
     }
 
     @Override
diff --git a/telecomm/java/android/telecom/ParcelableConnection.java b/telecomm/java/android/telecom/ParcelableConnection.java
index 540f388..e9dba68 100644
--- a/telecomm/java/android/telecom/ParcelableConnection.java
+++ b/telecomm/java/android/telecom/ParcelableConnection.java
@@ -37,6 +37,7 @@
     private final int mState;
     private final int mConnectionCapabilities;
     private final int mConnectionProperties;
+    private final int mSupportedAudioRoutes;
     private final Uri mAddress;
     private final int mAddressPresentation;
     private final String mCallerDisplayName;
@@ -57,6 +58,7 @@
             int state,
             int capabilities,
             int properties,
+            int supportedAudioRoutes,
             Uri address,
             int addressPresentation,
             String callerDisplayName,
@@ -74,6 +76,7 @@
         mState = state;
         mConnectionCapabilities = capabilities;
         mConnectionProperties = properties;
+        mSupportedAudioRoutes = supportedAudioRoutes;
         mAddress = address;
         mAddressPresentation = addressPresentation;
         mCallerDisplayName = callerDisplayName;
@@ -117,6 +120,10 @@
         return mConnectionProperties;
     }
 
+    public int getSupportedAudioRoutes() {
+        return mSupportedAudioRoutes;
+    }
+
     public Uri getHandle() {
         return mAddress;
     }
@@ -210,12 +217,14 @@
             source.readStringList(conferenceableConnectionIds);
             Bundle extras = Bundle.setDefusable(source.readBundle(classLoader), true);
             int properties = source.readInt();
+            int supportedAudioRoutes = source.readInt();
 
             return new ParcelableConnection(
                     phoneAccount,
                     state,
                     capabilities,
                     properties,
+                    supportedAudioRoutes,
                     address,
                     addressPresentation,
                     callerDisplayName,
@@ -264,5 +273,6 @@
         destination.writeStringList(mConferenceableConnectionIds);
         destination.writeBundle(mExtras);
         destination.writeInt(mConnectionProperties);
+        destination.writeInt(mSupportedAudioRoutes);
     }
 }
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 0457d63..ca54486 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -17,15 +17,6 @@
 package android.telecom;
 
 import android.annotation.SystemApi;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.res.Resources.NotFoundException;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Bundle;
@@ -37,7 +28,6 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-import java.util.MissingResourceException;
 
 /**
  * Represents a distinct method to place or receive a phone call. Apps which can place calls and
@@ -237,6 +227,7 @@
     private final CharSequence mLabel;
     private final CharSequence mShortDescription;
     private final List<String> mSupportedUriSchemes;
+    private final int mSupportedAudioRoutes;
     private final Icon mIcon;
     private final Bundle mExtras;
     private boolean mIsEnabled;
@@ -246,10 +237,12 @@
      * Helper class for creating a {@link PhoneAccount}.
      */
     public static class Builder {
+
         private PhoneAccountHandle mAccountHandle;
         private Uri mAddress;
         private Uri mSubscriptionAddress;
         private int mCapabilities;
+        private int mSupportedAudioRoutes = CallAudioState.ROUTE_ALL;
         private int mHighlightColor = NO_HIGHLIGHT_COLOR;
         private CharSequence mLabel;
         private CharSequence mShortDescription;
@@ -286,6 +279,7 @@
             mIsEnabled = phoneAccount.isEnabled();
             mExtras = phoneAccount.getExtras();
             mGroupId = phoneAccount.getGroupId();
+            mSupportedAudioRoutes = phoneAccount.getSupportedAudioRoutes();
         }
 
         /**
@@ -431,6 +425,18 @@
         }
 
         /**
+         * Sets the audio routes supported by this {@link PhoneAccount}.
+         *
+         * @param routes bit mask of available routes.
+         * @return The builder.
+         * @hide
+         */
+        public Builder setSupportedAudioRoutes(int routes) {
+            mSupportedAudioRoutes = routes;
+            return this;
+        }
+
+        /**
          * Creates an instance of a {@link PhoneAccount} based on the current builder settings.
          *
          * @return The {@link PhoneAccount}.
@@ -452,6 +458,7 @@
                     mShortDescription,
                     mSupportedUriSchemes,
                     mExtras,
+                    mSupportedAudioRoutes,
                     mIsEnabled,
                     mGroupId);
         }
@@ -468,6 +475,7 @@
             CharSequence shortDescription,
             List<String> supportedUriSchemes,
             Bundle extras,
+            int supportedAudioRoutes,
             boolean isEnabled,
             String groupId) {
         mAccountHandle = account;
@@ -480,6 +488,7 @@
         mShortDescription = shortDescription;
         mSupportedUriSchemes = Collections.unmodifiableList(supportedUriSchemes);
         mExtras = extras;
+        mSupportedAudioRoutes = supportedAudioRoutes;
         mIsEnabled = isEnabled;
         mGroupId = groupId;
     }
@@ -553,6 +562,17 @@
     }
 
     /**
+     * Determines if this {@code PhoneAccount} has routes specified by the passed in bit mask.
+     *
+     * @param route The routes to check.
+     * @return {@code true} if the phone account has the routes.
+     * @hide
+     */
+    public boolean hasAudioRoutes(int routes) {
+        return (mSupportedAudioRoutes & routes) == routes;
+    }
+
+    /**
      * A short label describing a {@code PhoneAccount}.
      *
      * @return A label for this {@code PhoneAccount}.
@@ -592,6 +612,15 @@
     }
 
     /**
+     * The audio routes supported by this {@code PhoneAccount}.
+     *
+     * @hide
+     */
+    public int getSupportedAudioRoutes() {
+        return mSupportedAudioRoutes;
+    }
+
+    /**
      * The icon to represent this {@code PhoneAccount}.
      *
      * @return The icon.
@@ -707,6 +736,7 @@
         out.writeByte((byte) (mIsEnabled ? 1 : 0));
         out.writeBundle(mExtras);
         out.writeString(mGroupId);
+        out.writeInt(mSupportedAudioRoutes);
     }
 
     public static final Creator<PhoneAccount> CREATOR
@@ -751,6 +781,7 @@
         mIsEnabled = in.readByte() == 1;
         mExtras = in.readBundle();
         mGroupId = in.readString();
+        mSupportedAudioRoutes = in.readInt();
     }
 
     @Override
@@ -760,7 +791,9 @@
                 .append("] PhoneAccount: ")
                 .append(mAccountHandle)
                 .append(" Capabilities: ")
-                .append(capabilitiesToString(mCapabilities))
+                .append(capabilitiesToString())
+                .append(" Audio Routes: ")
+                .append(audioRoutesToString())
                 .append(" Schemes: ");
         for (String scheme : mSupportedUriSchemes) {
             sb.append(scheme)
@@ -780,7 +813,7 @@
      * @param capabilities The capabilities bitmask.
      * @return String representation of the capabilities bitmask.
      */
-    private String capabilitiesToString(int capabilities) {
+    private String capabilitiesToString() {
         StringBuilder sb = new StringBuilder();
         if (hasCapabilities(CAPABILITY_SUPPORTS_VIDEO_CALLING)) {
             sb.append("SuppVideo ");
@@ -817,4 +850,23 @@
         }
         return sb.toString();
     }
+
+    private String audioRoutesToString() {
+        StringBuilder sb = new StringBuilder();
+
+        if (hasAudioRoutes(CallAudioState.ROUTE_BLUETOOTH)) {
+            sb.append("B");
+        }
+        if (hasAudioRoutes(CallAudioState.ROUTE_EARPIECE)) {
+            sb.append("E");
+        }
+        if (hasAudioRoutes(CallAudioState.ROUTE_SPEAKER)) {
+            sb.append("S");
+        }
+        if (hasAudioRoutes(CallAudioState.ROUTE_WIRED_HEADSET)) {
+            sb.append("W");
+        }
+
+        return sb.toString();
+    }
 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 1f06283..a0f5217 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -73,6 +73,15 @@
             KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL = "ignore_sim_network_locked_events_bool";
 
     /**
+     * When checking if a given number is the voicemail number, if this flag is true
+     * then in addition to comparing the given number to the voicemail number, we also compare it
+     * to the mdn. If this flag is false, the given number is only compared to the voicemail number.
+     * By default this value is false.
+     */
+    public static final String KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL =
+            "mdn_is_additional_voicemail_number_bool";
+
+    /**
      * Flag indicating whether the Phone app should provide a "Dismiss" button on the SIM network
      * unlock screen. The default value is true. If set to false, there will be *no way* to dismiss
      * the SIM network unlock screen if you don't enter the correct unlock code. (One important
@@ -1067,7 +1076,7 @@
      * is returned.
      * @hide
      */
-    public static final String FILTERED_CNAP_NAMES_STRING_ARRAY = "filtered_cnap_names_string_array";
+    public static final String KEY_FILTERED_CNAP_NAMES_STRING_ARRAY = "filtered_cnap_names_string_array";
 
     /**
      * The RCS configuration server URL. This URL is used to initiate RCS provisioning.
@@ -1097,6 +1106,11 @@
      */
     public static final String KEY_PERSIST_LPP_MODE_BOOL = "persist_lpp_mode_bool";
 
+    /**
+     * Carrier specified WiFi networks.
+     * @hide
+     */
+    public static final String KEY_CARRIER_WIFI_STRING_ARRAY = "carrier_wifi_string_array";
 
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
@@ -1143,6 +1157,7 @@
 
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONED_BOOL, false);
         sDefaults.putBoolean(KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL, false);
+        sDefaults.putBoolean(KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL, false);
         sDefaults.putBoolean(KEY_OPERATOR_SELECTION_EXPAND_BOOL, true);
         sDefaults.putBoolean(KEY_PREFER_2G_BOOL, true);
         sDefaults.putBoolean(KEY_SHOW_APN_SETTING_CDMA_BOOL, false);
@@ -1291,10 +1306,11 @@
         sDefaults.putStringArray(KEY_IMS_REASONINFO_MAPPING_STRING_ARRAY, null);
         sDefaults.putBoolean(KEY_ENHANCED_4G_LTE_TITLE_VARIANT_BOOL, false);
         sDefaults.putBoolean(KEY_NOTIFY_VT_HANDOVER_TO_WIFI_FAILURE_BOOL, false);
-        sDefaults.putStringArray(FILTERED_CNAP_NAMES_STRING_ARRAY, null);
+        sDefaults.putStringArray(KEY_FILTERED_CNAP_NAMES_STRING_ARRAY, null);
         sDefaults.putBoolean(KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, false);
         sDefaults.putBoolean(KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL, false);
         sDefaults.putBoolean(KEY_PERSIST_LPP_MODE_BOOL, false);
+        sDefaults.putStringArray(KEY_CARRIER_WIFI_STRING_ARRAY, null);
     }
 
     /**
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index addf7ef..4137853 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -141,6 +141,16 @@
     }
 
     /**
+     * Get the GSM timing advance between 0..219 symbols (normally 0..63).
+     * Integer.MAX_VALUE is reported when there is no RR connection.
+     * Refer to 3GPP 45.010 Sec 5.8
+     * @return the current GSM timing advance, if available.
+     */
+    public int getTimingAdvance() {
+        return mTimingAdvance;
+    }
+
+    /**
      * Get the signal strength as dBm
      */
     @Override
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 434caad..0d07a40 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -220,8 +220,10 @@
     }
 
     /**
-     * Get the timing advance value for LTE.
-     * See 3GPP xxxx
+     * Get the timing advance value for LTE, as a value between 0..63.
+     * Integer.MAX_VALUE is reported when there is no active RRC
+     * connection. Refer to 3GPP 36.213 Sec 4.2.3
+     * @return the LTE timing advance, if available.
      */
     public int getTimingAdvance() {
         return mTimingAdvance;
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 152b868..6f51c6e 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -29,6 +29,7 @@
 import android.location.CountryDetector;
 import android.net.Uri;
 import android.os.SystemProperties;
+import android.os.PersistableBundle;
 import android.provider.Contacts;
 import android.provider.ContactsContract;
 import android.telecom.PhoneAccount;
@@ -2106,7 +2107,7 @@
      *   number provided by the RIL and SIM card. The caller must have
      *   the READ_PHONE_STATE credential.
      *
-     * @param context a non-null {@link Context}.
+     * @param context {@link Context}.
      * @param subId the subscription id of the SIM.
      * @param number the number to look up.
      * @return true if the number is in the list of voicemail. False
@@ -2115,25 +2116,54 @@
      * @hide
      */
     public static boolean isVoiceMailNumber(Context context, int subId, String number) {
-        String vmNumber;
+        String vmNumber, mdn;
         try {
             final TelephonyManager tm;
             if (context == null) {
                 tm = TelephonyManager.getDefault();
+                if (DBG) log("isVoiceMailNumber: default tm");
             } else {
                 tm = TelephonyManager.from(context);
+                if (DBG) log("isVoiceMailNumber: tm from context");
             }
             vmNumber = tm.getVoiceMailNumber(subId);
+            mdn = tm.getLine1Number(subId);
+            if (DBG) log("isVoiceMailNumber: mdn=" + mdn + ", vmNumber=" + vmNumber
+                    + ", number=" + number);
         } catch (SecurityException ex) {
+            if (DBG) log("isVoiceMailNumber: SecurityExcpetion caught");
             return false;
         }
         // Strip the separators from the number before comparing it
         // to the list.
         number = extractNetworkPortionAlt(number);
+        if (TextUtils.isEmpty(number)) {
+            if (DBG) log("isVoiceMailNumber: number is empty after stripping");
+            return false;
+        }
 
-        // compare tolerates null so we need to make sure that we
-        // don't return true when both are null.
-        return !TextUtils.isEmpty(number) && compare(number, vmNumber);
+        // check if the carrier considers MDN to be an additional voicemail number
+        boolean compareWithMdn = false;
+        if (context != null) {
+            CarrierConfigManager configManager = (CarrierConfigManager)
+                    context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+            if (configManager != null) {
+                PersistableBundle b = configManager.getConfigForSubId(subId);
+                if (b != null) {
+                    compareWithMdn = b.getBoolean(CarrierConfigManager.
+                            KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL);
+                    if (DBG) log("isVoiceMailNumber: compareWithMdn=" + compareWithMdn);
+                }
+            }
+        }
+
+        if (compareWithMdn) {
+            if (DBG) log("isVoiceMailNumber: treating mdn as additional vm number");
+            return compare(number, vmNumber) || compare(number, mdn);
+        } else {
+            if (DBG) log("isVoiceMailNumber: returning regular compare");
+            return compare(number, vmNumber);
+        }
     }
 
     /**
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 11d84c1..7a83979 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -20,6 +20,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.telephony.Rlog;
+import android.text.TextUtils;
 
 /**
  * Contains phone state and service related information.
@@ -590,6 +591,24 @@
     }
 
     /**
+     * Get current registered operator name in long alphanumeric format if
+     * available or short otherwise.
+     *
+     * @see #getOperatorAlphaLong
+     * @see #getOperatorAlphaShort
+     *
+     * @return name of operator, null if unregistered or unknown
+     * @hide
+     */
+    public String getOperatorAlpha() {
+        if (TextUtils.isEmpty(mVoiceOperatorAlphaLong)) {
+            return mVoiceOperatorAlphaShort;
+        }
+
+        return mVoiceOperatorAlphaLong;
+    }
+
+    /**
      * Get current registered operator numeric id.
      *
      * In GSM/UMTS, numeric format is 3 digit country code plus 2 or 3 digit
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 457fd88..918ef5e 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2275,6 +2275,8 @@
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      *   OR
      *   {@link android.Manifest.permission#READ_SMS}
+     *   OR
+     *   {@link android.Manifest.permission#READ_PHONE_NUMBER}
      * <p>
      * The default SMS app can also use this.
      */
@@ -2290,6 +2292,8 @@
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      *   OR
      *   {@link android.Manifest.permission#READ_SMS}
+     *   OR
+     *   {@link android.Manifest.permission#READ_PHONE_NUMBER}
      * <p>
      * The default SMS app can also use this.
      *
diff --git a/telephony/java/com/android/ims/internal/IImsVideoCallProvider.aidl b/telephony/java/com/android/ims/internal/IImsVideoCallProvider.aidl
index 39e83c6..0da27e1 100644
--- a/telephony/java/com/android/ims/internal/IImsVideoCallProvider.aidl
+++ b/telephony/java/com/android/ims/internal/IImsVideoCallProvider.aidl
@@ -43,7 +43,7 @@
 oneway interface IImsVideoCallProvider {
     void setCallback(IImsVideoCallCallback callback);
 
-    void setCamera(String cameraId);
+    void setCamera(String cameraId, int uid);
 
     void setPreviewSurface(in Surface surface);
 
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index d4104bd..20c303e 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -438,7 +438,7 @@
         // check to see if these are recognized numbers, and use shortcuts if we can.
         if (PhoneNumberUtils.isLocalEmergencyNumber(context, number)) {
             cw.event = EVENT_EMERGENCY_NUMBER;
-        } else if (PhoneNumberUtils.isVoiceMailNumber(subId, number)) {
+        } else if (PhoneNumberUtils.isVoiceMailNumber(context, subId, number)) {
             cw.event = EVENT_VOICEMAIL_NUMBER;
         } else {
             cw.event = EVENT_NEW_QUERY;
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index fee3aa5..1bd5b1d 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -524,14 +524,6 @@
         throw new UnsupportedOperationException();
     }
 
-    /** @hide */
-    @Override
-    public Drawable getManagedUserBadgedDrawable(Drawable drawable, Rect badgeLocation,
-            int badgeDensity) {
-        throw new UnsupportedOperationException();
-    }
-
-
     @Override
     public Drawable getUserBadgedIcon(Drawable icon, UserHandle user) {
         throw new UnsupportedOperationException();
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
index 51adfe7..ff61754 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -661,9 +661,13 @@
     // The IPv6 all nodes address ff02::1
     private static final byte[] IPV6_ALL_NODES_ADDRESS =
             { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
+    private static final byte[] IPV6_ALL_ROUTERS_ADDRESS =
+            { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 };
 
     private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
+    private static final int ICMP6_ROUTER_SOLICITATION = 133;
     private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
+    private static final int ICMP6_NEIGHBOR_SOLICITATION = 135;
     private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
 
     private static final int ICMP6_RA_HEADER_LEN = 16;
@@ -798,6 +802,12 @@
         put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_NODES_ADDRESS);
         assertDrop(program, packet.array());
 
+        // Verify ICMPv6 RS to any is dropped
+        packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_SOLICITATION);
+        assertDrop(program, packet.array());
+        put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_ROUTERS_ADDRESS);
+        assertDrop(program, packet.array());
+
         apfFilter.shutdown();
     }
 
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index ca2d2e7..6ca59b0 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -91,7 +91,7 @@
             while r in raw: raw.remove(r)
         self.split = list(raw)
 
-        for r in ["method", "public", "protected", "static", "final", "deprecated", "abstract"]:
+        for r in ["method", "public", "protected", "static", "final", "deprecated", "abstract", "default"]:
             while r in raw: raw.remove(r)
 
         self.typ = raw[0]
diff --git a/tools/bit/main.cpp b/tools/bit/main.cpp
index 4974a44..868d90a 100644
--- a/tools/bit/main.cpp
+++ b/tools/bit/main.cpp
@@ -79,6 +79,7 @@
     string tabPattern;
 
     // For build/install/test
+    bool noRestart;
     bool reboot;
     vector<Target*> targets;
 
@@ -89,6 +90,7 @@
 Options::Options()
     :runHelp(false),
      runTab(false),
+     noRestart(false),
      reboot(false),
      targets()
 {
@@ -285,6 +287,7 @@
     fprintf(out, "  -i     Install the targets\n");
     fprintf(out, "  -t     Run the tests\n");
     fprintf(out, "\n");
+    fprintf(out, "  -n     Don't reboot or restart\n");
     fprintf(out, "  -r     If the runtime needs to be restarted, do a full reboot\n");
     fprintf(out, "         instead\n");
     fprintf(out, "\n");
@@ -431,6 +434,9 @@
                         flagTest = true;
                         anyPhases = true;
                         break;
+                    case 'n':
+                        options->noRestart = true;
+                        break;
                     case 'r':
                         options->reboot = true;
                         break;
@@ -558,7 +564,7 @@
  * Run the build, install, and test actions.
  */
 void
-run_phases(vector<Target*> targets, bool reboot)
+run_phases(vector<Target*> targets, const Options& options)
 {
     int err = 0;
 
@@ -676,40 +682,44 @@
             check_device_property("ro.build.id", buildId);
 
             // Stop & Sync
-            err = run_adb("shell", "stop", NULL);
-            check_error(err);
+            if (!options.noRestart) {
+                err = run_adb("shell", "stop", NULL);
+                check_error(err);
+            }
             err = run_adb("remount", NULL);
             check_error(err);
             err = run_adb("sync", "system", NULL);
             check_error(err);
 
-            if (reboot) {
-                print_status("Rebooting");
+            if (!options.noRestart) {
+                if (options.reboot) {
+                    print_status("Rebooting");
 
-                err = run_adb("reboot", NULL);
-                check_error(err);
-                err = run_adb("wait-for-device", NULL);
-                check_error(err);
-            } else {
-                print_status("Restarting the runtime");
+                    err = run_adb("reboot", NULL);
+                    check_error(err);
+                    err = run_adb("wait-for-device", NULL);
+                    check_error(err);
+                } else {
+                    print_status("Restarting the runtime");
 
-                err = run_adb("shell", "setprop", "sys.boot_completed", "0", NULL);
-                check_error(err);
-                err = run_adb("shell", "start", NULL);
-                check_error(err);
-            }
-
-            while (true) {
-                string completed = get_system_property("sys.boot_completed", &err);
-                check_error(err);
-                if (completed == "1") {
-                    break;
+                    err = run_adb("shell", "setprop", "sys.boot_completed", "0", NULL);
+                    check_error(err);
+                    err = run_adb("shell", "start", NULL);
+                    check_error(err);
                 }
-                sleep(2);
+
+                while (true) {
+                    string completed = get_system_property("sys.boot_completed", &err);
+                    check_error(err);
+                    if (completed == "1") {
+                        break;
+                    }
+                    sleep(2);
+                }
+                sleep(1);
+                err = run_adb("shell", "wm", "dismiss-keyguard", NULL);
+                check_error(err);
             }
-            sleep(1);
-            err = run_adb("shell", "wm", "dismiss-keyguard", NULL);
-            check_error(err);
         }
     }
 
@@ -976,7 +986,7 @@
         exit(0);
     } else {
         // Normal run
-        run_phases(options.targets, options.reboot);
+        run_phases(options.targets, options);
     }
 
     return 0;
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index 9da65a6..35cf903 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -80,7 +80,7 @@
 
     public BridgeTypedArray(Resources resources, BridgeContext context, int len,
             boolean platformFile) {
-        super(resources, null, null, 0);
+        super(resources);
         mBridgeResources = resources;
         mContext = context;
         mPlatformFile = platformFile;
diff --git a/tools/layoutlib/bridge/src/com/android/internal/view/animation/NativeInterpolatorFactoryHelper_Delegate.java b/tools/layoutlib/bridge/src/com/android/internal/view/animation/NativeInterpolatorFactoryHelper_Delegate.java
index 0f39e80..ffce1a0 100644
--- a/tools/layoutlib/bridge/src/com/android/internal/view/animation/NativeInterpolatorFactoryHelper_Delegate.java
+++ b/tools/layoutlib/bridge/src/com/android/internal/view/animation/NativeInterpolatorFactoryHelper_Delegate.java
@@ -104,7 +104,7 @@
 
         @Override
         public float getInterpolation(float input) {
-            float lutpos = input * mSize;
+            float lutpos = input * (mSize - 1);
             if (lutpos >= (mSize - 1)) {
                 return mValues[mSize - 1];
             }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
index 0b169bd..f47b105 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
@@ -495,12 +495,6 @@
     }
 
     @Override
-    public Drawable getManagedUserBadgedDrawable(Drawable drawable, Rect badgeLocation,
-        int badgeDensity) {
-        return null;
-    }
-
-    @Override
     public Drawable getUserBadgedIcon(Drawable icon, UserHandle user) {
         return null;
     }
diff --git a/tools/preload2/preload-tool b/tools/preload2/preload-tool
index 36dbc1c..322b62f 100644
--- a/tools/preload2/preload-tool
+++ b/tools/preload2/preload-tool
@@ -34,4 +34,4 @@
 PROG_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
 ANDROID_ROOT=$PROG_DIR/..
 
-java -cp $ANDROID_ROOT/framework/preload2.jar com.android.preload.Main
+java -cp $ANDROID_ROOT/framework/preload2.jar com.android.preload.Main $@
diff --git a/tools/preload2/src/com/android/preload/Main.java b/tools/preload2/src/com/android/preload/Main.java
index cc54a8d..c42a19b 100644
--- a/tools/preload2/src/com/android/preload/Main.java
+++ b/tools/preload2/src/com/android/preload/Main.java
@@ -33,12 +33,17 @@
 import com.android.preload.classdataretrieval.hprof.Hprof;
 import com.android.preload.classdataretrieval.jdwp.JDWPClassDataRetriever;
 import com.android.preload.ui.IUI;
+import com.android.preload.ui.SequenceUI;
 import com.android.preload.ui.SwingUI;
 
+import java.io.File;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.NoSuchElementException;
 
 import javax.swing.Action;
 import javax.swing.DefaultListModel;
@@ -86,13 +91,24 @@
             + "android.webkit.WebViewClassic\\$1$" + "|" + "java.lang.ProcessManager$" + "|"
             + "(.*\\$NoPreloadHolder$)";
 
+    public final static String SCAN_ALL_CMD = "scan-all";
+    public final static String SCAN_PACKAGE_CMD = "scan";
+    public final static String COMPUTE_FILE_CMD = "comp";
+    public final static String EXPORT_CMD = "export";
+    public final static String IMPORT_CMD = "import";
+
     /**
      * @param args
      */
     public static void main(String[] args) {
-        Main m = new Main(new SwingUI());
-        top = m;
+        Main m;
+        if (args.length > 0 && args[0].equals("--seq")) {
+            m = createSequencedMain(args);
+        } else {
+            m = new Main(new SwingUI());
+        }
 
+        top = m;
         m.startUp();
     }
 
@@ -130,6 +146,70 @@
         ui.prepare(clientListModel, dataTableModel, actions);
     }
 
+    /**
+     * @param args
+     * @return
+     */
+    private static Main createSequencedMain(String[] args) {
+        SequenceUI ui = new SequenceUI();
+        Main main = new Main(ui);
+
+        Iterator<String> it = Arrays.asList(args).iterator();
+        it.next();  // --seq
+        // Setup
+        ui.choice("#" + it.next());  // Device.
+        ui.confirmNo();              // Prepare: no.
+        // Actions
+        try {
+            while (it.hasNext()) {
+                String op = it.next();
+                // Operation: Scan a single package
+                if (SCAN_PACKAGE_CMD.equals(op)) {
+                    System.out.println("Scanning package.");
+                    ui.action(ScanPackageAction.class);
+                    ui.client(it.next());
+                // Operation: Scan all packages
+                } else if (SCAN_ALL_CMD.equals(op)) {
+                    System.out.println("Scanning all packages.");
+                    ui.action(ScanAllPackagesAction.class);
+                // Operation: Export the output to a file
+                } else if (EXPORT_CMD.equals(op)) {
+                    System.out.println("Exporting data.");
+                    ui.action(ExportAction.class);
+                    ui.output(new File(it.next()));
+                // Operation: Import the input from a file or directory
+                } else if (IMPORT_CMD.equals(op)) {
+                    System.out.println("Importing data.");
+                    File file = new File(it.next());
+                    if (!file.exists()) {
+                        throw new RuntimeException(
+                                String.format("File does not exist, %s.", file.getAbsolutePath()));
+                    } else if (file.isFile()) {
+                        ui.action(ImportAction.class);
+                        ui.input(file);
+                    } else if (file.isDirectory()) {
+                        for (File content : file.listFiles()) {
+                            ui.action(ImportAction.class);
+                            ui.input(content);
+                        }
+                    }
+                // Operation: Compute preloaded classes with specific threshold
+                } else if (COMPUTE_FILE_CMD.equals(op)) {
+                    System.out.println("Compute preloaded classes.");
+                    ui.action(ComputeThresholdXAction.class);
+                    ui.input(it.next());
+                    ui.confirmYes();
+                    ui.output(new File(it.next()));
+                }
+            }
+        } catch (NoSuchElementException e) {
+            System.out.println("Failed to parse action sequence correctly.");
+            throw e;
+        }
+
+        return main;
+    }
+
     public static IUI getUI() {
         return top.ui;
     }
diff --git a/tools/preload2/src/com/android/preload/ui/SequenceUI.java b/tools/preload2/src/com/android/preload/ui/SequenceUI.java
new file mode 100644
index 0000000..dc6a4f3
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/ui/SequenceUI.java
@@ -0,0 +1,222 @@
+package com.android.preload.ui;
+
+import com.android.ddmlib.Client;
+import com.android.ddmlib.ClientData;
+import java.io.File;
+import java.util.LinkedList;
+import java.util.List;
+import javax.swing.Action;
+import javax.swing.ListModel;
+import javax.swing.table.TableModel;
+
+public class SequenceUI implements IUI {
+
+    private ListModel<Client> clientListModel;
+    @SuppressWarnings("unused")
+    private TableModel dataTableModel;
+    private List<Action> actions;
+
+    private List<Object> sequence = new LinkedList<>();
+
+    public SequenceUI() {
+    }
+
+    @Override
+    public boolean isSingleThreaded() {
+        return true;
+    }
+
+    @Override
+    public void prepare(ListModel<Client> clientListModel, TableModel dataTableModel,
+            List<Action> actions) {
+        this.clientListModel = clientListModel;
+        this.dataTableModel = dataTableModel;
+        this.actions = actions;
+    }
+
+    public SequenceUI action(Action a) {
+        sequence.add(a);
+        return this;
+    }
+
+    public SequenceUI action(Class<? extends Action> actionClass) {
+        for (Action a : actions) {
+            if (actionClass.equals(a.getClass())) {
+                sequence.add(a);
+                return this;
+            }
+        }
+        throw new IllegalArgumentException("No action of class " + actionClass + " found.");
+    }
+
+    public SequenceUI confirmYes() {
+        sequence.add(Boolean.TRUE);
+        return this;
+    }
+
+    public SequenceUI confirmNo() {
+        sequence.add(Boolean.FALSE);
+        return this;
+    }
+
+    public SequenceUI input(String input) {
+        sequence.add(input);
+        return this;
+    }
+
+    public SequenceUI input(File... f) {
+        sequence.add(f);
+        return this;
+    }
+
+    public SequenceUI output(File f) {
+        sequence.add(f);
+        return this;
+    }
+
+    public SequenceUI tableRow(int i) {
+        sequence.add(i);
+        return this;
+    }
+
+    private class ClientSelector {
+        private String pkg;
+
+        public ClientSelector(String pkg) {
+            this.pkg = pkg;
+        }
+
+        public Client getClient() {
+            for (int i = 0; i < clientListModel.getSize(); i++) {
+                ClientData cd = clientListModel.getElementAt(i).getClientData();
+                if (cd != null) {
+                    String s = cd.getClientDescription();
+                    if (pkg.equals(s)) {
+                        return clientListModel.getElementAt(i);
+                    }
+                }
+            }
+            throw new RuntimeException("Didn't find client " + pkg);
+        }
+    }
+
+    public SequenceUI client(String pkg) {
+        sequence.add(new ClientSelector(pkg));
+        return this;
+    }
+
+    public SequenceUI choice(String pattern) {
+        sequence.add(pattern);
+        return this;
+    }
+
+    @Override
+    public void ready() {
+        // Run the actions.
+        // No iterator or foreach loop as the sequence will be emptied while running.
+        try {
+            while (!sequence.isEmpty()) {
+                Object next = sequence.remove(0);
+                if (next instanceof Action) {
+                    ((Action)next).actionPerformed(null);
+                } else {
+                    throw new IllegalStateException("Didn't expect a non-action: " + next);
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace(System.out);
+        }
+
+        // Now shut down.
+        System.exit(0);
+    }
+
+    @Override
+    public Client getSelectedClient() {
+        Object next = sequence.remove(0);
+        if (next instanceof ClientSelector) {
+            return ((ClientSelector)next).getClient();
+        }
+        throw new IllegalStateException("Unexpected: " + next);
+    }
+
+    @Override
+    public int getSelectedDataTableRow() {
+        Object next = sequence.remove(0);
+        if (next instanceof Integer) {
+            return ((Integer)next).intValue();
+        }
+        throw new IllegalStateException("Unexpected: " + next);
+    }
+
+    @Override
+    public void showWaitDialog() {
+    }
+
+    @Override
+    public void updateWaitDialog(String s) {
+        System.out.println(s);
+    }
+
+    @Override
+    public void hideWaitDialog() {
+    }
+
+    @Override
+    public void showMessageDialog(String s) {
+        System.out.println(s);
+    }
+
+    @Override
+    public boolean showConfirmDialog(String title, String message) {
+        Object next = sequence.remove(0);
+        if (next instanceof Boolean) {
+            return ((Boolean)next).booleanValue();
+        }
+        throw new IllegalStateException("Unexpected: " + next);
+    }
+
+    @Override
+    public String showInputDialog(String message) {
+        Object next = sequence.remove(0);
+        if (next instanceof String) {
+            return (String)next;
+        }
+        throw new IllegalStateException("Unexpected: " + next);
+    }
+
+    @Override
+    public <T> T showChoiceDialog(String title, String message, T[] choices) {
+        Object next = sequence.remove(0);
+        if (next instanceof String) {
+            String s = (String)next;
+            for (T t : choices) {
+                if (t.toString().contains(s)) {
+                    return t;
+                }
+            }
+            return null;
+        }
+        throw new IllegalStateException("Unexpected: " + next);
+    }
+
+    @Override
+    public File showSaveDialog() {
+        Object next = sequence.remove(0);
+        if (next instanceof File) {
+            System.out.println(next);
+            return (File)next;
+        }
+        throw new IllegalStateException("Unexpected: " + next);
+    }
+
+    @Override
+    public File[] showOpenDialog(boolean multi) {
+        Object next = sequence.remove(0);
+        if (next instanceof File[]) {
+            return (File[])next;
+        }
+        throw new IllegalStateException("Unexpected: " + next);
+    }
+
+}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 24cd275..69e9fcd 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -98,10 +98,22 @@
          */
         public static final int OSEN = 5;
 
+        /**
+         * IEEE 802.11r Fast BSS Transition with PSK authentication.
+         * @hide
+         */
+        public static final int FT_PSK = 6;
+
+        /**
+         * IEEE 802.11r Fast BSS Transition with EAP authentication.
+         * @hide
+         */
+        public static final int FT_EAP = 7;
+
         public static final String varName = "key_mgmt";
 
         public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP", "IEEE8021X",
-                "WPA2_PSK", "OSEN" };
+                "WPA2_PSK", "OSEN", "FT_PSK", "FT_EAP" };
     }
 
     /**
@@ -685,12 +697,22 @@
     /**
      * @hide
      * A hint about whether or not the network represented by this WifiConfiguration
-     * is metered.
+     * is metered. This is hinted at via the meteredHint bit on DHCP results set in
+     * {@link com.android.server.wifi.WifiStateMachine}, or via a network score in
+     * {@link com.android.server.wifi.ExternalScoreEvaluator}.
      */
     public boolean meteredHint;
 
     /**
      * @hide
+     * Indicates if a user has specified the WifiConfiguration to be metered. Users
+     * can toggle if a network is metered within Settings -> Data Usage -> Network
+     * Restrictions.
+     */
+    public boolean meteredOverride;
+
+    /**
+     * @hide
      * Setting this value will force scan results associated with this configuration to
      * be included in the bucket of networks that are externally scored.
      * If not set, associated scan results will be treated as legacy saved networks and
@@ -1367,6 +1389,7 @@
         didSelfAdd = false;
         ephemeral = false;
         meteredHint = false;
+        meteredOverride = false;
         useExternalScores = false;
         validatedInternetAccess = false;
         mIpConfiguration = new IpConfiguration();
@@ -1470,9 +1493,11 @@
         if (this.validatedInternetAccess) sbuf.append(" validatedInternetAccess");
         if (this.ephemeral) sbuf.append(" ephemeral");
         if (this.meteredHint) sbuf.append(" meteredHint");
+        if (this.meteredOverride) sbuf.append(" meteredOverride");
         if (this.useExternalScores) sbuf.append(" useExternalScores");
         if (this.didSelfAdd || this.selfAdded || this.validatedInternetAccess
-            || this.ephemeral || this.meteredHint || this.useExternalScores) {
+            || this.ephemeral || this.meteredHint || this.meteredOverride
+            || this.useExternalScores) {
             sbuf.append("\n");
         }
         sbuf.append(" KeyMgmt:");
@@ -1897,6 +1922,7 @@
             validatedInternetAccess = source.validatedInternetAccess;
             ephemeral = source.ephemeral;
             meteredHint = source.meteredHint;
+            meteredOverride = source.meteredOverride;
             useExternalScores = source.useExternalScores;
             if (source.visibility != null) {
                 visibility = new Visibility(source.visibility);
@@ -1978,6 +2004,7 @@
         dest.writeInt(validatedInternetAccess ? 1 : 0);
         dest.writeInt(ephemeral ? 1 : 0);
         dest.writeInt(meteredHint ? 1 : 0);
+        dest.writeInt(meteredOverride ? 1 : 0);
         dest.writeInt(useExternalScores ? 1 : 0);
         dest.writeInt(creatorUid);
         dest.writeInt(lastConnectUid);
@@ -2049,6 +2076,7 @@
                 config.validatedInternetAccess = in.readInt() != 0;
                 config.ephemeral = in.readInt() != 0;
                 config.meteredHint = in.readInt() != 0;
+                config.meteredOverride = in.readInt() != 0;
                 config.useExternalScores = in.readInt() != 0;
                 config.creatorUid = in.readInt();
                 config.lastConnectUid = in.readInt();
diff --git a/wifi/java/android/net/wifi/aware/ConfigRequest.java b/wifi/java/android/net/wifi/aware/ConfigRequest.java
index 4aacbae..4b21b15 100644
--- a/wifi/java/android/net/wifi/aware/ConfigRequest.java
+++ b/wifi/java/android/net/wifi/aware/ConfigRequest.java
@@ -22,7 +22,7 @@
 /**
  * Defines a request object to configure a Wi-Fi Aware network. Built using
  * {@link ConfigRequest.Builder}. Configuration is requested using
- * {@link WifiAwareManager#attach(android.os.Handler, WifiAwareAttachCallback)}.
+ * {@link WifiAwareManager#attach(WifiAwareAttachCallback, android.os.Handler)}.
  * Note that the actual achieved configuration may be different from the
  * requested configuration - since different applications may request different
  * configurations.
diff --git a/wifi/java/android/net/wifi/aware/LvBufferUtils.java b/wifi/java/android/net/wifi/aware/LvBufferUtils.java
deleted file mode 100644
index 3265243..0000000
--- a/wifi/java/android/net/wifi/aware/LvBufferUtils.java
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.aware;
-
-import android.annotation.Nullable;
-
-import libcore.io.Memory;
-
-import java.nio.ByteOrder;
-import java.util.Iterator;
-
-/**
- * Utility class to construct and parse byte arrays using the LV format -
- * Length/Value format. The utilities accept a configuration of the size of
- * the Length field.
- *
- * @hide PROPOSED_AWARE_API
- */
-public class LvBufferUtils {
-    private LvBufferUtils() {
-        // no reason to ever create this class
-    }
-
-    /**
-     * Utility class to construct byte arrays using the LV format - Length/Value.
-     * <p>
-     * A constructor is created specifying the size of the Length (L) field.
-     * <p>
-     * The byte array is either provided (using
-     * {@link LvBufferUtils.LvConstructor#wrap(byte[])}) or allocated (using
-     * {@link LvBufferUtils.LvConstructor#allocate(int)}).
-     * <p>
-     * Values are added to the structure using the {@code LvConstructor.put*()}
-     * methods.
-     * <p>
-     * The final byte array is obtained using {@link LvBufferUtils.LvConstructor#getArray()}.
-     */
-    public static class LvConstructor {
-        private TlvBufferUtils.TlvConstructor mTlvImpl;
-
-        /**
-         * Define a LV constructor with the specified size of the Length (L) field.
-         *
-         * @param lengthSize Number of bytes used for the Length (L) field.
-         *            Values of 1 or 2 bytes are allowed.
-         */
-        public LvConstructor(int lengthSize) {
-            mTlvImpl = new TlvBufferUtils.TlvConstructor(0, lengthSize);
-        }
-
-        /**
-         * Set the byte array to be used to construct the LV.
-         *
-         * @param array Byte array to be formatted.
-         * @return The constructor to facilitate chaining
-         *         {@code ctr.putXXX(..).putXXX(..)}.
-         */
-        public LvBufferUtils.LvConstructor wrap(@Nullable byte[] array) {
-            mTlvImpl.wrap(array);
-            return this;
-        }
-
-        /**
-         * Allocates a new byte array to be used ot construct a LV.
-         *
-         * @param capacity The size of the byte array to be allocated.
-         * @return The constructor to facilitate chaining
-         *         {@code ctr.putXXX(..).putXXX(..)}.
-         */
-        public LvBufferUtils.LvConstructor allocate(int capacity) {
-            mTlvImpl.allocate(capacity);
-            return this;
-        }
-
-        /**
-         * Copies a byte into the LV array.
-         *
-         * @param b The byte to be inserted into the structure.
-         * @return The constructor to facilitate chaining
-         *         {@code ctr.putXXX(..).putXXX(..)}.
-         */
-        public LvBufferUtils.LvConstructor putByte(byte b) {
-            mTlvImpl.putByte(0, b);
-            return this;
-        }
-
-        /**
-         * Copies a byte array into the LV.
-         *
-         * @param array The array to be copied into the LV structure.
-         * @param offset Start copying from the array at the specified offset.
-         * @param length Copy the specified number (length) of bytes from the
-         *            array.
-         * @return The constructor to facilitate chaining
-         *         {@code ctr.putXXX(..).putXXX(..)}.
-         */
-        public LvBufferUtils.LvConstructor putByteArray(@Nullable byte[] array, int offset,
-                int length) {
-            mTlvImpl.putByteArray(0, array, offset, length);
-            return this;
-        }
-
-        /**
-         * Copies a byte array into the LV.
-         *
-         * @param array The array to be copied (in full) into the LV structure.
-         * @return The constructor to facilitate chaining
-         *         {@code ctr.putXXX(..).putXXX(..)}.
-         */
-        public LvBufferUtils.LvConstructor putByteArray(int type, @Nullable byte[] array) {
-            return putByteArray(array, 0, (array == null) ? 0 : array.length);
-        }
-
-        /**
-         * Places a zero length element (i.e. Length field = 0) into the LV.
-         *
-         * @return The constructor to facilitate chaining
-         *         {@code ctr.putXXX(..).putXXX(..)}.
-         */
-        public LvBufferUtils.LvConstructor putZeroLengthElement() {
-            mTlvImpl.putZeroLengthElement(0);
-            return this;
-        }
-
-        /**
-         * Copies short into the LV.
-         *
-         * @param data The short to be inserted into the structure.
-         * @return The constructor to facilitate chaining
-         *         {@code ctr.putXXX(..).putXXX(..)}.
-         */
-        public LvBufferUtils.LvConstructor putShort(short data) {
-            mTlvImpl.putShort(0, data);
-            return this;
-        }
-
-        /**
-         * Copies integer into the LV.
-         *
-         * @param data The integer to be inserted into the structure.
-         * @return The constructor to facilitate chaining
-         *         {@code ctr.putXXX(..).putXXX(..)}.
-         */
-        public LvBufferUtils.LvConstructor putInt(int data) {
-            mTlvImpl.putInt(0, data);
-            return this;
-        }
-
-        /**
-         * Copies a String's byte representation into the LV.
-         *
-         * @param data The string whose bytes are to be inserted into the
-         *            structure.
-         * @return The constructor to facilitate chaining
-         *         {@code ctr.putXXX(..).putXXX(..)}.
-         */
-        public LvBufferUtils.LvConstructor putString(@Nullable String data) {
-            mTlvImpl.putString(0, data);
-            return this;
-        }
-
-        /**
-         * Returns the constructed LV formatted byte-array. This array is a copy of the wrapped
-         * or allocated array - truncated to just the significant bytes - i.e. those written into
-         * the LV.
-         *
-         * @return The byte array containing the LV formatted structure.
-         */
-        public byte[] getArray() {
-            return mTlvImpl.getArray();
-        }
-    }
-
-    /**
-     * Utility class used when iterating over an LV formatted byte-array. Use
-     * {@link LvBufferUtils.LvIterable} to iterate over array. A {@link LvBufferUtils.LvElement}
-     * represents each entry in a LV formatted byte-array.
-     */
-    public static class LvElement {
-        /**
-         * The Length (L) field of the current LV element.
-         */
-        public int length;
-
-        /**
-         * The Value (V) field - a raw byte array representing the current LV
-         * element where the entry starts at {@link LvBufferUtils.LvElement#offset}.
-         */
-        public byte[] refArray;
-
-        /**
-         * The offset to be used into {@link LvBufferUtils.LvElement#refArray} to access the
-         * raw data representing the current LV element.
-         */
-        public int offset;
-
-        private LvElement(int length, @Nullable byte[] refArray, int offset) {
-            this.length = length;
-            this.refArray = refArray;
-            this.offset = offset;
-        }
-
-        /**
-         * Utility function to return a byte representation of a LV element of
-         * length 1. Note: an attempt to call this function on a LV item whose
-         * {@link LvBufferUtils.LvElement#length} is != 1 will result in an exception.
-         *
-         * @return byte representation of current LV element.
-         */
-        public byte getByte() {
-            if (length != 1) {
-                throw new IllegalArgumentException(
-                        "Accesing a byte from a LV element of length " + length);
-            }
-            return refArray[offset];
-        }
-
-        /**
-         * Utility function to return a short representation of a LV element of
-         * length 2. Note: an attempt to call this function on a LV item whose
-         * {@link LvBufferUtils.LvElement#length} is != 2 will result in an exception.
-         *
-         * @return short representation of current LV element.
-         */
-        public short getShort() {
-            if (length != 2) {
-                throw new IllegalArgumentException(
-                        "Accesing a short from a LV element of length " + length);
-            }
-            return Memory.peekShort(refArray, offset, ByteOrder.BIG_ENDIAN);
-        }
-
-        /**
-         * Utility function to return an integer representation of a LV element
-         * of length 4. Note: an attempt to call this function on a LV item
-         * whose {@link LvBufferUtils.LvElement#length} is != 4 will result in an exception.
-         *
-         * @return integer representation of current LV element.
-         */
-        public int getInt() {
-            if (length != 4) {
-                throw new IllegalArgumentException(
-                        "Accesing an int from a LV element of length " + length);
-            }
-            return Memory.peekInt(refArray, offset, ByteOrder.BIG_ENDIAN);
-        }
-
-        /**
-         * Utility function to return a String representation of a LV element.
-         *
-         * @return String representation of the current LV element.
-         */
-        public String getString() {
-            return new String(refArray, offset, length);
-        }
-    }
-
-    /**
-     * Utility class to iterate over a LV formatted byte-array.
-     */
-    public static class LvIterable implements Iterable<LvBufferUtils.LvElement> {
-        private final TlvBufferUtils.TlvIterable mTlvIterable;
-
-        /**
-         * Constructs an LvIterable object - specifying the format of the LV
-         * (the size of the Length field), and the byte array whose data is to be parsed.
-         *
-         * @param lengthSize Number of bytes sued for the Length (L) field.
-         *            Values values are 1 or 2 bytes.
-         * @param array The LV formatted byte-array to parse.
-         */
-        public LvIterable(int lengthSize, @Nullable byte[] array) {
-            mTlvIterable = new TlvBufferUtils.TlvIterable(0, lengthSize, array);
-        }
-
-        /**
-         * Prints out a parsed representation of the LV-formatted byte array.
-         * Whenever possible bytes, shorts, and integer are printed out (for
-         * fields whose length is 1, 2, or 4 respectively).
-         */
-        @Override
-        public String toString() {
-            return mTlvIterable.toString();
-        }
-
-        /**
-         * Returns an iterator to step through a LV formatted byte-array. The
-         * individual elements returned by the iterator are {@link LvBufferUtils.LvElement}.
-         */
-        @Override
-        public Iterator<LvBufferUtils.LvElement> iterator() {
-            return new Iterator<LvBufferUtils.LvElement>() {
-                private Iterator<TlvBufferUtils.TlvElement> mTlvIterator = mTlvIterable.iterator();
-
-                @Override
-                public boolean hasNext() {
-                    return mTlvIterator.hasNext();
-                }
-
-                @Override
-                public LvBufferUtils.LvElement next() {
-                    TlvBufferUtils.TlvElement tlvE = mTlvIterator.next();
-
-                    return new LvElement(tlvE.length, tlvE.refArray, tlvE.offset);
-                }
-
-                @Override
-                public void remove() {
-                    throw new UnsupportedOperationException();
-                }
-            };
-        }
-    }
-
-    /**
-     * Validates that a LV array is constructed correctly. I.e. that its specified Length
-     * fields correctly fill the specified length (and do not overshoot).
-     *
-     * @param array The LV array to verify.
-     * @param lengthSize The size (in bytes) of the length field. Valid values are 1 or 2.
-     * @return A boolean indicating whether the array is valid (true) or invalid (false).
-     */
-    public static boolean isValid(@Nullable byte[] array, int lengthSize) {
-        return TlvBufferUtils.isValid(array, 0, lengthSize);
-    }
-}
diff --git a/wifi/java/android/net/wifi/aware/PublishConfig.java b/wifi/java/android/net/wifi/aware/PublishConfig.java
index ba493a0..3925bd7 100644
--- a/wifi/java/android/net/wifi/aware/PublishConfig.java
+++ b/wifi/java/android/net/wifi/aware/PublishConfig.java
@@ -28,6 +28,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
+import java.util.List;
 
 /**
  * Defines the configuration of a Aware publish session. Built using
@@ -84,7 +85,8 @@
     /** @hide */
     public final boolean mEnableTerminateNotification;
 
-    private PublishConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter,
+    /** @hide */
+    public PublishConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter,
             int publishType, int publichCount, int ttlSec, boolean enableTerminateNotification) {
         mServiceName = serviceName;
         mServiceSpecificInfo = serviceSpecificInfo;
@@ -99,9 +101,9 @@
     public String toString() {
         return "PublishConfig [mServiceName='" + mServiceName + ", mServiceSpecificInfo='" + (
                 (mServiceSpecificInfo == null) ? "null" : HexEncoding.encode(mServiceSpecificInfo))
-                + ", mTxFilter=" + (new LvBufferUtils.LvIterable(1, mMatchFilter)).toString()
-                + ", mPublishType=" + mPublishType + ", mPublishCount=" + mPublishCount
-                + ", mTtlSec=" + mTtlSec + ", mEnableTerminateNotification="
+                + ", mMatchFilter=" + (new TlvBufferUtils.TlvIterable(0, 1,
+                mMatchFilter)).toString() + ", mPublishType=" + mPublishType + ", mPublishCount="
+                + mPublishCount + ", mTtlSec=" + mTtlSec + ", mEnableTerminateNotification="
                 + mEnableTerminateNotification + "]";
     }
 
@@ -186,7 +188,7 @@
             throws IllegalArgumentException {
         WifiAwareUtils.validateServiceName(mServiceName);
 
-        if (!LvBufferUtils.isValid(mMatchFilter, 1)) {
+        if (!TlvBufferUtils.isValid(mMatchFilter, 0, 1)) {
             throw new IllegalArgumentException(
                     "Invalid txFilter configuration - LV fields do not match up to length");
         }
@@ -281,18 +283,17 @@
          * The match filter for a publish session. Used to determine whether a service
          * discovery occurred - in addition to relying on the service name.
          * <p>
-         * Format is an LV byte array: a single byte Length field followed by L bytes (the value of
-         * the Length field) of a value blob.
-         * <p>
          *     Optional. Empty by default.
          *
-         * @param matchFilter The byte-array containing the LV formatted match filter.
+         * @param matchFilter A list of match filter entries (each of which is an arbitrary byte
+         *                    array).
          *
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
-        public Builder setMatchFilter(@Nullable byte[] matchFilter) {
-            mMatchFilter = matchFilter;
+        public Builder setMatchFilter(@Nullable List<byte[]> matchFilter) {
+            mMatchFilter = new TlvBufferUtils.TlvConstructor(0, 1).allocateAndPut(
+                    matchFilter).getArray();
             return this;
         }
 
diff --git a/wifi/java/android/net/wifi/aware/SubscribeConfig.java b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
index 5e14f8f..0fe69a8 100644
--- a/wifi/java/android/net/wifi/aware/SubscribeConfig.java
+++ b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
@@ -28,6 +28,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
+import java.util.List;
 
 /**
  * Defines the configuration of a Aware subscribe session. Built using
@@ -106,7 +107,8 @@
     /** @hide */
     public final boolean mEnableTerminateNotification;
 
-    private SubscribeConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter,
+    /** @hide */
+    public SubscribeConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter,
             int subscribeType, int publichCount, int ttlSec, int matchStyle,
             boolean enableTerminateNotification) {
         mServiceName = serviceName;
@@ -123,10 +125,11 @@
     public String toString() {
         return "SubscribeConfig [mServiceName='" + mServiceName + ", mServiceSpecificInfo='" + (
                 (mServiceSpecificInfo == null) ? "null" : HexEncoding.encode(mServiceSpecificInfo))
-                + ", mMatchFilter=" + (new LvBufferUtils.LvIterable(1, mMatchFilter)).toString()
-                + ", mSubscribeType=" + mSubscribeType + ", mSubscribeCount=" + mSubscribeCount
-                + ", mTtlSec=" + mTtlSec + ", mMatchType=" + mMatchStyle
-                + ", mEnableTerminateNotification=" + mEnableTerminateNotification + "]";
+                + ", mMatchFilter=" + (new TlvBufferUtils.TlvIterable(0, 1,
+                mMatchFilter)).toString() + ", mSubscribeType=" + mSubscribeType
+                + ", mSubscribeCount=" + mSubscribeCount + ", mTtlSec=" + mTtlSec + ", mMatchType="
+                + mMatchStyle + ", mEnableTerminateNotification=" + mEnableTerminateNotification
+                + "]";
     }
 
     @Override
@@ -213,7 +216,7 @@
             throws IllegalArgumentException {
         WifiAwareUtils.validateServiceName(mServiceName);
 
-        if (!LvBufferUtils.isValid(mMatchFilter, 1)) {
+        if (!TlvBufferUtils.isValid(mMatchFilter, 0, 1)) {
             throw new IllegalArgumentException(
                     "Invalid matchFilter configuration - LV fields do not match up to length");
         }
@@ -313,18 +316,17 @@
          * The match filter for a subscribe session. Used to determine whether a service
          * discovery occurred - in addition to relying on the service name.
          * <p>
-         * Format is an LV byte array: a single byte Length field followed by L bytes (the value of
-         * the Length field) of a value blob.
-         * <p>
          *     Optional. Empty by default.
          *
-         * @param matchFilter The byte-array containing the LV formatted match filter.
+         * @param matchFilter A list of match filter entries (each of which is an arbitrary byte
+         *                    array).
          *
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
-        public Builder setMatchFilter(@Nullable byte[] matchFilter) {
-            mMatchFilter = matchFilter;
+        public Builder setMatchFilter(@Nullable List<byte[]> matchFilter) {
+            mMatchFilter = new TlvBufferUtils.TlvConstructor(0, 1).allocateAndPut(
+                    matchFilter).getArray();
             return this;
         }
 
@@ -403,7 +405,7 @@
          * single match session (corresponding to the same publish action on the
          * peer) reported to the host (using the
          * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
-         * byte[], byte[])}). The options are: only report the first match and ignore the rest
+         * byte[], List)}). The options are: only report the first match and ignore the rest
          * {@link SubscribeConfig#MATCH_STYLE_FIRST_ONLY} or report every single
          * match {@link SubscribeConfig#MATCH_STYLE_ALL} (the default).
          *
diff --git a/wifi/java/android/net/wifi/aware/TlvBufferUtils.java b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
index 56c9069..29f10e9 100644
--- a/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
+++ b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
@@ -22,8 +22,10 @@
 
 import java.nio.BufferOverflowException;
 import java.nio.ByteOrder;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Iterator;
+import java.util.List;
 import java.util.NoSuchElementException;
 
 /**
@@ -32,7 +34,7 @@
  * the Type field and the Length field. A Type field size of 0 is allowed -
  * allowing usage for LV (no T) array formats.
  *
- * @hide PROPOSED_AWARE_API
+ * @hide
  */
 public class TlvBufferUtils {
     private TlvBufferUtils() {
@@ -111,6 +113,31 @@
         }
 
         /**
+         * Creates a TLV array (of the previously specified Type and Length sizes) from the input
+         * list. Allocates an array matching the contents (and required Type and Length
+         * fields), copies the contents, and set the Length fields. The Type field is set to 0.
+         *
+         * @param list A list of fields to be added to the TLV buffer.
+         * @return The constructor of the TLV.
+         */
+        public TlvConstructor allocateAndPut(@Nullable List<byte[]> list) {
+            if (list != null) {
+                int size = 0;
+                for (byte[] field : list) {
+                    size += mTypeSize + mLengthSize;
+                    if (field != null) {
+                        size += field.length;
+                    }
+                }
+                allocate(size);
+                for (byte[] field : list) {
+                    putByteArray(0, field);
+                }
+            }
+            return this;
+        }
+
+        /**
          * Copies a byte into the TLV with the indicated type. For an LV
          * formatted structure (i.e. typeLength=0 in {@link TlvConstructor
          * TlvConstructor(int, int)} ) the type field is ignored.
@@ -319,6 +346,10 @@
             this.length = length;
             this.refArray = refArray;
             this.offset = offset;
+
+            if (offset + length > refArray.length) {
+                throw new BufferOverflowException();
+            }
         }
 
         /**
@@ -393,7 +424,7 @@
          * @param typeSize Number of bytes used for the Type (T) field. Valid
          *            values are 0 (i.e. indicating the format is LV rather than
          *            TLV), 1, and 2 bytes.
-         * @param lengthSize Number of bytes sued for the Length (L) field.
+         * @param lengthSize Number of bytes used for the Length (L) field.
          *            Values values are 1 or 2 bytes.
          * @param array The TLV formatted byte-array to parse.
          */
@@ -450,6 +481,18 @@
         }
 
         /**
+         * Returns a List with the raw contents (no types) of the iterator.
+         */
+        public List<byte[]> toList() {
+            List<byte[]> list = new ArrayList<>();
+            for (TlvElement tlv : this) {
+                list.add(Arrays.copyOfRange(tlv.refArray, tlv.offset, tlv.offset + tlv.length));
+            }
+
+            return list;
+        }
+
+        /**
          * Returns an iterator to step through a TLV formatted byte-array. The
          * individual elements returned by the iterator are {@link TlvElement}.
          */
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java b/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java
index 072ccab..092aa34 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java
@@ -69,8 +69,9 @@
 
     /**
      * Returns the maximum length of byte array that can be used to specify a Aware match filter.
-     * Restricts the parameters of the {@link PublishConfig.Builder#setMatchFilter(byte[])} and
-     * {@link SubscribeConfig.Builder#setMatchFilter(byte[])}.
+     * Restricts the parameters of the
+     * {@link PublishConfig.Builder#setMatchFilter(java.util.List)} and
+     * {@link SubscribeConfig.Builder#setMatchFilter(java.util.List)}.
      *
      * @return A positive integer, maximum legngth of byte array for Aware discovery match filter.
      */
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java b/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java
index e8335d1..2812ad4 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java
@@ -35,7 +35,7 @@
  *     <li>Sending messages: {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[])} or
  *     {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[], int)} methods.
  *     <li>Creating a network-specifier when requesting a Aware connection:
- *     {@link #createNetworkSpecifier(int, WifiAwareManager.PeerHandle, byte[])}.
+ *     {@link #createNetworkSpecifier(WifiAwareManager.PeerHandle, byte[])}.
  * </ul>
  * The {@link #destroy()} method must be called to destroy discovery sessions once they are
  * no longer needed.
@@ -140,7 +140,7 @@
      * Sends a message to the specified destination. Aware messages are transmitted in the context
      * of a discovery session - executed subsequent to a publish/subscribe
      * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
-     * byte[], byte[])} event.
+     * byte[], java.util.List)} event.
      * <p>
      *     Aware messages are not guaranteed delivery. Callbacks on
      *     {@link WifiAwareDiscoverySessionCallback} indicate message was transmitted successfully,
@@ -154,7 +154,7 @@
      *
      * @param peerHandle The peer's handle for the message. Must be a result of an
      * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
-     * byte[], byte[])} or
+     * byte[], java.util.List)} or
      * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
      * byte[])} events.
      * @param messageId An arbitrary integer used by the caller to identify the message. The same
@@ -187,7 +187,7 @@
      * Sends a message to the specified destination. Aware messages are transmitted in the context
      * of a discovery session - executed subsequent to a publish/subscribe
      * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
-     * byte[], byte[])} event.
+     * byte[], java.util.List)} event.
      * <p>
      *     Aware messages are not guaranteed delivery. Callbacks on
      *     {@link WifiAwareDiscoverySessionCallback} indicate message was transmitted successfully,
@@ -203,7 +203,7 @@
      *
      * @param peerHandle The peer's handle for the message. Must be a result of an
      * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
-     * byte[], byte[])} or
+     * byte[], java.util.List)} or
      * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
      * byte[])} events.
      * @param messageId An arbitrary integer used by the caller to identify the message. The same
@@ -220,7 +220,7 @@
     /**
      * Start a ranging operation with the specified peers. The peer IDs are obtained from an
      * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
-     * byte[], byte[])} or
+     * byte[], java.util.List)} or
      * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
      * byte[])} operation - can
      * only range devices which are part of an ongoing discovery session.
@@ -260,13 +260,13 @@
      * OOB (out-of-band) mechanism then use the alternative
      * {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])} method - which uses the
      * peer's MAC address.
+     * <p>
+     * Note: per the Wi-Fi Aware specification the roles are fixed - a Subscriber is an INITIATOR
+     * and a Publisher is a RESPONDER.
      *
-     * @param role The role of this device:
-     * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
-     * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}
      * @param peerHandle The peer's handle obtained through
      * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
-     * byte[], byte[])} or
+     * byte[], java.util.List)} or
      * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
      * byte[])}. On a RESPONDER this value is used to gate the acceptance of a connection request
      *                   from only that peer. A RESPONDER may specified a null - indicating that
@@ -283,8 +283,8 @@
      * android.net.ConnectivityManager.NetworkCallback)}
      * [or other varieties of that API].
      */
-    public String createNetworkSpecifier(@WifiAwareManager.DataPathRole int role,
-            @Nullable WifiAwareManager.PeerHandle peerHandle, @Nullable byte[] token) {
+    public String createNetworkSpecifier(@Nullable WifiAwareManager.PeerHandle peerHandle,
+            @Nullable byte[] token) {
         if (mTerminated) {
             Log.w(TAG, "createNetworkSpecifier: called on terminated session");
             return null;
@@ -295,6 +295,10 @@
                 return null;
             }
 
+            int role = this instanceof WifiAwareSubscribeDiscoverySession
+                    ? WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
+                    : WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
+
             return mgr.createNetworkSpecifier(mClientId, role, mSessionId, peerHandle, token);
         }
     }
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java
index 6331c9c..fdf0d01 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java
@@ -21,6 +21,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.List;
 
 /**
  * Base class for Aware session events callbacks. Should be extended by
@@ -130,11 +131,10 @@
      * @param serviceSpecificInfo The service specific information (arbitrary
      *            byte array) provided by the peer as part of its discovery
      *            configuration.
-     * @param matchFilter The filter (Tx on advertiser and Rx on listener) which
-     *            resulted in this service discovery.
+     * @param matchFilter The filter which resulted in this service discovery.
      */
     public void onServiceDiscovered(WifiAwareManager.PeerHandle peerHandle,
-            byte[] serviceSpecificInfo, byte[] matchFilter) {
+            byte[] serviceSpecificInfo, List<byte[]> matchFilter) {
         /* empty */
     }
 
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index a34ef47..029794d 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -45,7 +45,9 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
+import java.nio.BufferOverflowException;
 import java.util.Arrays;
+import java.util.List;
 
 /**
  * This class provides the primary API for managing Wi-Fi Aware operations:
@@ -63,7 +65,7 @@
  * <li>Create a Aware network specifier to be used with
  * {@link ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)}
  * to set-up a Aware connection with a peer. Refer to
- * {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, PeerHandle, byte[])} and
+ * {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(PeerHandle, byte[])} and
  * {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])}.
  * </ul>
  * <p>
@@ -114,7 +116,7 @@
  *        {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
  *        <li>{@link NetworkRequest.Builder#setNetworkSpecifier(String)} using
  *        {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])} or
- *        {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, PeerHandle, byte[])}.
+ *        {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(PeerHandle, byte[])}.
  *    </ul>
  *
  * @hide PROPOSED_AWARE_API
@@ -224,7 +226,7 @@
      * Connection creation role is that of INITIATOR. Used to create a network specifier string
      * when requesting a Aware network.
      *
-     * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, PeerHandle, byte[])
+     * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(PeerHandle, byte[])
      * @see WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])
      */
     public static final int WIFI_AWARE_DATA_PATH_ROLE_INITIATOR = 0;
@@ -233,7 +235,7 @@
      * Connection creation role is that of RESPONDER. Used to create a network specifier string
      * when requesting a Aware network.
      *
-     * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, PeerHandle, byte[])
+     * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(PeerHandle, byte[])
      * @see WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])
      */
     public static final int WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1;
@@ -874,12 +876,22 @@
                         case CALLBACK_SESSION_TERMINATED:
                             onProxySessionTerminated(msg.arg1);
                             break;
-                        case CALLBACK_MATCH:
-                            mOriginalCallback.onServiceDiscovered(
-                                    new PeerHandle(msg.arg1),
+                        case CALLBACK_MATCH: {
+                            List<byte[]> matchFilter = null;
+                            byte[] arg = msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2);
+                            try {
+                                matchFilter = new TlvBufferUtils.TlvIterable(0, 1, arg).toList();
+                            } catch (BufferOverflowException e) {
+                                matchFilter = null;
+                                Log.e(TAG, "onServiceDiscovered: invalid match filter byte array '"
+                                        + new String(HexEncoding.encode(arg))
+                                        + "' - cannot be parsed: e=" + e);
+                            }
+                            mOriginalCallback.onServiceDiscovered(new PeerHandle(msg.arg1),
                                     msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE),
-                                    msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2));
+                                    matchFilter);
                             break;
+                        }
                         case CALLBACK_MESSAGE_SEND_SUCCESS:
                             mOriginalCallback.onMessageSendSucceeded(msg.arg1);
                             break;
@@ -966,7 +978,7 @@
         @Override
         public void onMessageReceived(int peerId, byte[] message) {
             if (VDBG) {
-                Log.v(TAG, "onMessageReceived: peerId='" + peerId);
+                Log.v(TAG, "onMessageReceived: peerId=" + peerId);
             }
 
             Message msg = mHandler.obtainMessage(CALLBACK_MESSAGE_RECEIVED);
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
index acb60a4..005895a 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
@@ -193,8 +193,8 @@
      *     This API is targeted for applications which can obtain the peer MAC address using OOB
      *     (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
      *     when using Aware discovery use the alternative network specifier method -
-     *     {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int,
-     *     WifiAwareManager.PeerHandle, byte[])}.
+     *     {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(WifiAwareManager.PeerHandle,
+     *     byte[])}.
      *
      * @param role  The role of this device:
      *              {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
@@ -211,7 +211,7 @@
      *
      * @return A string to be used to construct
      * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
-     * {@link android.net.ConnectivityManager#requestNetwork(NetworkRequest,
+     * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
      * android.net.ConnectivityManager.NetworkCallback)}
      * [or other varieties of that API].
      */
diff --git a/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java b/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java
index 4b6957b..15641ab 100644
--- a/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java
@@ -24,6 +24,10 @@
 import org.junit.Test;
 import org.junit.rules.ErrorCollector;
 
+import java.nio.BufferOverflowException;
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Unit test harness for TlvBufferUtils class.
  */
@@ -47,9 +51,9 @@
         collector.checkThat("tlv11-correct-construction",
                 tlv11.getArray(), equalTo(new byte[]{0, 1, 2, 2, 3, 0, 1, 2}));
 
-        LvBufferUtils.LvConstructor tlv01 = new LvBufferUtils.LvConstructor(1);
+        TlvBufferUtils.TlvConstructor tlv01 = new TlvBufferUtils.TlvConstructor(0, 1);
         tlv01.allocate(15);
-        tlv01.putByte((byte) 2);
+        tlv01.putByte(0, (byte) 2);
         tlv01.putByteArray(2, new byte[] {
                 0, 1, 2 });
 
@@ -60,10 +64,63 @@
                 TlvBufferUtils.isValid(tlv11.getArray(), 1, 1),
                 equalTo(true));
         collector.checkThat("tlv01-valid",
-                LvBufferUtils.isValid(tlv01.getArray(), 1),
+                TlvBufferUtils.isValid(tlv01.getArray(), 0, 1),
                 equalTo(true));
     }
 
+    /**
+     * Verify that can build a valid TLV from a List of byte[].
+     */
+    @Test
+    public void testTlvListOperations() {
+        byte[] entry1 = { 1, 2, 3 };
+        byte[] entry2 = { 4, 5 };
+        byte[] entry3 = new byte[0];
+        List<byte[]> data = new ArrayList<>();
+        data.add(entry1);
+        data.add(entry2);
+        data.add(entry3);
+        data.add(null); // zero-length should work
+
+        TlvBufferUtils.TlvConstructor tlv01 = new TlvBufferUtils.TlvConstructor(0, 1);
+        tlv01.allocateAndPut(data);
+        byte[] tlvData = tlv01.getArray();
+        List<byte[]> parsedList = new TlvBufferUtils.TlvIterable(0, 1, tlvData).toList();
+
+        collector.checkThat("tlvData-correct-length", tlvData.length,
+                equalTo(entry1.length + 1 + entry2.length + 1 + entry3.length + 1 + 1));
+        collector.checkThat("parsedList-correct-length", parsedList.size(), equalTo(4));
+        collector.checkThat("parsedList-entry1", parsedList.get(0), equalTo(entry1));
+        collector.checkThat("parsedList-entry2", parsedList.get(1), equalTo(entry2));
+        collector.checkThat("parsedList-entry3", parsedList.get(2), equalTo(entry3));
+        collector.checkThat("parsedList-entry4", parsedList.get(3), equalTo(new byte[0]));
+    }
+
+    /**
+     * Verify that can parse a (correctly formatted) byte array to a list.
+     */
+    @Test
+    public void testTlvParseToList() {
+        byte[] validTlv01 = { 0, 1, 55, 2, 33, 66, 0 };
+
+        List<byte[]> parsedList = new TlvBufferUtils.TlvIterable(0, 1, validTlv01).toList();
+
+        collector.checkThat("parsedList-entry1", parsedList.get(0), equalTo(new byte[0]));
+        collector.checkThat("parsedList-entry2", parsedList.get(1), equalTo(new byte[] { 55 }));
+        collector.checkThat("parsedList-entry3", parsedList.get(2), equalTo(new byte[] { 33, 66 }));
+        collector.checkThat("parsedList-entry4", parsedList.get(3), equalTo(new byte[0]));
+    }
+
+    /**
+     * Verify that an exception is thrown when trying to parse an invalid array.
+     */
+    @Test(expected = BufferOverflowException.class)
+    public void testTlvParseToListError() {
+        byte[] invalidTlv01 = { 0, 1, 55, 2, 55, 66, 3 }; // bad data
+
+        List<byte[]> data = new TlvBufferUtils.TlvIterable(0, 1, invalidTlv01).toList();
+    }
+
     @Test
     public void testTlvIterate() {
         final String ascii = "ABC";
@@ -137,7 +194,7 @@
                 TlvBufferUtils.isValid(tlv22.getArray(), 2, 2),
                 equalTo(true));
         collector.checkThat("tlv02-valid",
-                LvBufferUtils.isValid(tlv02.getArray(), 2),
+                TlvBufferUtils.isValid(tlv02.getArray(), 0, 2),
                 equalTo(true));
     }
 
@@ -211,15 +268,15 @@
      */
     @Test
     public void testTlvInvalidByteArray() {
-        LvBufferUtils.LvConstructor tlv01 = new LvBufferUtils.LvConstructor(1);
+        TlvBufferUtils.TlvConstructor tlv01 = new TlvBufferUtils.TlvConstructor(0, 1);
         tlv01.allocate(15);
-        tlv01.putByte((byte) 2);
+        tlv01.putByte(0, (byte) 2);
         tlv01.putByteArray(2, new byte[]{0, 1, 2});
 
         byte[] array = tlv01.getArray();
         array[0] = 10;
 
         collector.checkThat("tlv01-invalid",
-                LvBufferUtils.isValid(array, 1), equalTo(false));
+                TlvBufferUtils.isValid(array, 0, 1), equalTo(false));
     }
 }
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index b30ecf7..24c0127 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -49,6 +49,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.List;
+
 /**
  * Unit test harness for WifiAwareManager class.
  */
@@ -276,7 +278,7 @@
         final PublishConfig publishConfig = new PublishConfig.Builder().build();
         final WifiAwareManager.PeerHandle peerHandle = new WifiAwareManager.PeerHandle(873);
         final String string1 = "hey from here...";
-        final String string2 = "some other arbitrary string...";
+        final byte[] matchFilter = { 1, 12, 2, 31, 32 };
         final int messageId = 2123;
         final int reason = AWARE_STATUS_ERROR;
 
@@ -292,6 +294,8 @@
                 .forClass(WifiAwarePublishDiscoverySession.class);
         ArgumentCaptor<WifiAwareManager.PeerHandle> peerIdCaptor = ArgumentCaptor.forClass(
                 WifiAwareManager.PeerHandle.class);
+        ArgumentCaptor<List<byte[]>> matchFilterCaptor = ArgumentCaptor.forClass(
+                (Class) List.class);
 
         // (0) connect + success
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
@@ -314,8 +318,7 @@
 
         // (3) ...
         publishSession.getValue().sendMessage(peerHandle, messageId, string1.getBytes());
-        sessionProxyCallback.getValue().onMatch(peerHandle.peerId, string1.getBytes(),
-                string2.getBytes());
+        sessionProxyCallback.getValue().onMatch(peerHandle.peerId, string1.getBytes(), matchFilter);
         sessionProxyCallback.getValue().onMessageReceived(peerHandle.peerId, string1.getBytes());
         sessionProxyCallback.getValue().onMessageSendFail(messageId, reason);
         sessionProxyCallback.getValue().onMessageSendSuccess(messageId);
@@ -324,13 +327,22 @@
         inOrder.verify(mockAwareService).sendMessage(eq(clientId), eq(sessionId),
                 eq(peerHandle.peerId), eq(string1.getBytes()), eq(messageId), eq(0));
         inOrder.verify(mockSessionCallback).onServiceDiscovered(peerIdCaptor.capture(),
-                eq(string1.getBytes()), eq(string2.getBytes()));
-        assertEquals(((WifiAwareManager.PeerHandle) peerIdCaptor.getValue()).peerId,
-                peerHandle.peerId);
+                eq(string1.getBytes()),
+                matchFilterCaptor.capture());
+
+        // note: need to capture/compare elements since the Mockito eq() is a shallow comparator
+        List<byte[]> parsedMatchFilter = new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList();
+        collector.checkThat("match-filter-size", parsedMatchFilter.size(),
+                equalTo(matchFilterCaptor.getValue().size()));
+        collector.checkThat("match-filter-entry0", parsedMatchFilter.get(0),
+                equalTo(matchFilterCaptor.getValue().get(0)));
+        collector.checkThat("match-filter-entry1", parsedMatchFilter.get(1),
+                equalTo(matchFilterCaptor.getValue().get(1)));
+
+        assertEquals(peerIdCaptor.getValue().peerId, peerHandle.peerId);
         inOrder.verify(mockSessionCallback).onMessageReceived(peerIdCaptor.capture(),
                 eq(string1.getBytes()));
-        assertEquals(((WifiAwareManager.PeerHandle) peerIdCaptor.getValue()).peerId,
-                peerHandle.peerId);
+        assertEquals(peerIdCaptor.getValue().peerId, peerHandle.peerId);
         inOrder.verify(mockSessionCallback).onMessageSendFailed(eq(messageId));
         inOrder.verify(mockSessionCallback).onMessageSendSucceeded(eq(messageId));
 
@@ -418,7 +430,7 @@
         final SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
         final WifiAwareManager.PeerHandle peerHandle = new WifiAwareManager.PeerHandle(873);
         final String string1 = "hey from here...";
-        final String string2 = "some other arbitrary string...";
+        final byte[] matchFilter = { 1, 12, 3, 31, 32 }; // bad data!
         final int messageId = 2123;
         final int reason = AWARE_STATUS_ERROR;
 
@@ -456,8 +468,7 @@
 
         // (3) ...
         subscribeSession.getValue().sendMessage(peerHandle, messageId, string1.getBytes());
-        sessionProxyCallback.getValue().onMatch(peerHandle.peerId, string1.getBytes(),
-                string2.getBytes());
+        sessionProxyCallback.getValue().onMatch(peerHandle.peerId, string1.getBytes(), matchFilter);
         sessionProxyCallback.getValue().onMessageReceived(peerHandle.peerId, string1.getBytes());
         sessionProxyCallback.getValue().onMessageSendFail(messageId, reason);
         sessionProxyCallback.getValue().onMessageSendSuccess(messageId);
@@ -466,13 +477,11 @@
         inOrder.verify(mockAwareService).sendMessage(eq(clientId), eq(sessionId),
                 eq(peerHandle.peerId), eq(string1.getBytes()), eq(messageId), eq(0));
         inOrder.verify(mockSessionCallback).onServiceDiscovered(peerIdCaptor.capture(),
-                eq(string1.getBytes()), eq(string2.getBytes()));
-        assertEquals(((WifiAwareManager.PeerHandle) peerIdCaptor.getValue()).peerId,
-                peerHandle.peerId);
+                eq(string1.getBytes()), (List<byte[]>) isNull());
+        assertEquals((peerIdCaptor.getValue()).peerId, peerHandle.peerId);
         inOrder.verify(mockSessionCallback).onMessageReceived(peerIdCaptor.capture(),
                 eq(string1.getBytes()));
-        assertEquals(((WifiAwareManager.PeerHandle) peerIdCaptor.getValue()).peerId,
-                peerHandle.peerId);
+        assertEquals((peerIdCaptor.getValue()).peerId, peerHandle.peerId);
         inOrder.verify(mockSessionCallback).onMessageSendFailed(eq(messageId));
         inOrder.verify(mockSessionCallback).onMessageSendSucceeded(eq(messageId));
 
@@ -676,8 +685,7 @@
     public void testSubscribeConfigBuilder() {
         final String serviceName = "some_service_or_other";
         final String serviceSpecificInfo = "long arbitrary string with some info";
-        final byte[] matchFilter = {
-                0, 1, 16, 1, 22 };
+        final byte[] matchFilter = { 1, 16, 1, 22 };
         final int subscribeType = SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE;
         final int subscribeCount = 10;
         final int subscribeTtl = 15;
@@ -685,7 +693,8 @@
         final boolean enableTerminateNotification = false;
 
         SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName)
-                .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(matchFilter)
+                .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(
+                        new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList())
                 .setSubscribeType(subscribeType)
                 .setSubscribeCount(subscribeCount).setTtlSec(subscribeTtl).setMatchStyle(matchStyle)
                 .setTerminateNotificationEnabled(enableTerminateNotification).build();
@@ -709,8 +718,7 @@
     public void testSubscribeConfigParcel() {
         final String serviceName = "some_service_or_other";
         final String serviceSpecificInfo = "long arbitrary string with some info";
-        final byte[] matchFilter = {
-                0, 1, 16, 1, 22 };
+        final byte[] matchFilter = { 1, 16, 1, 22 };
         final int subscribeType = SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE;
         final int subscribeCount = 10;
         final int subscribeTtl = 15;
@@ -718,7 +726,8 @@
         final boolean enableTerminateNotification = true;
 
         SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName)
-                .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(matchFilter)
+                .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(
+                        new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList())
                 .setSubscribeType(subscribeType)
                 .setSubscribeCount(subscribeCount).setTtlSec(subscribeTtl).setMatchStyle(matchStyle)
                 .setTerminateNotificationEnabled(enableTerminateNotification).build();
@@ -780,15 +789,15 @@
     public void testPublishConfigBuilder() {
         final String serviceName = "some_service_or_other";
         final String serviceSpecificInfo = "long arbitrary string with some info";
-        final byte[] matchFilter = {
-                0, 1, 16, 1, 22 };
+        final byte[] matchFilter = { 1, 16, 1, 22 };
         final int publishType = PublishConfig.PUBLISH_TYPE_SOLICITED;
         final int publishCount = 10;
         final int publishTtl = 15;
         final boolean enableTerminateNotification = false;
 
         PublishConfig publishConfig = new PublishConfig.Builder().setServiceName(serviceName)
-                .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(matchFilter)
+                .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(
+                        new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList())
                 .setPublishType(publishType)
                 .setPublishCount(publishCount).setTtlSec(publishTtl)
                 .setTerminateNotificationEnabled(enableTerminateNotification).build();
@@ -809,15 +818,15 @@
     public void testPublishConfigParcel() {
         final String serviceName = "some_service_or_other";
         final String serviceSpecificInfo = "long arbitrary string with some info";
-        final byte[] matchFilter = {
-                0, 1, 16, 1, 22 };
+        final byte[] matchFilter = { 1, 16, 1, 22 };
         final int publishType = PublishConfig.PUBLISH_TYPE_SOLICITED;
         final int publishCount = 10;
         final int publishTtl = 15;
         final boolean enableTerminateNotification = false;
 
         PublishConfig publishConfig = new PublishConfig.Builder().setServiceName(serviceName)
-                .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(matchFilter)
+                .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(
+                        new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList())
                 .setPublishType(publishType)
                 .setPublishCount(publishCount).setTtlSec(publishTtl)
                 .setTerminateNotificationEnabled(enableTerminateNotification).build();
@@ -945,7 +954,7 @@
         final int clientId = 4565;
         final int sessionId = 123;
         final WifiAwareManager.PeerHandle peerHandle = new WifiAwareManager.PeerHandle(123412);
-        final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR;
+        final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
         final String token = "Some arbitrary token string - can really be anything";
         final ConfigRequest configRequest = new ConfigRequest.Builder().build();
         final PublishConfig publishConfig = new PublishConfig.Builder().build();
@@ -982,7 +991,7 @@
         inOrder.verify(mockSessionCallback).onPublishStarted(publishSession.capture());
 
         // (3) request a network specifier from the session
-        String networkSpecifier = publishSession.getValue().createNetworkSpecifier(role, peerHandle,
+        String networkSpecifier = publishSession.getValue().createNetworkSpecifier(peerHandle,
                 token.getBytes());
 
         // validate format