Merge "Add single use App specific incoming SMSes"
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 552103d..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 \
@@ -338,6 +340,7 @@
 	core/java/com/android/internal/backup/IObbBackupService.aidl \
 	core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl \
 	core/java/com/android/internal/policy/IKeyguardDrawnCallback.aidl \
+	core/java/com/android/internal/policy/IKeyguardDismissCallback.aidl \
 	core/java/com/android/internal/policy/IKeyguardExitCallback.aidl \
 	core/java/com/android/internal/policy/IKeyguardService.aidl \
 	core/java/com/android/internal/policy/IKeyguardStateCallback.aidl \
@@ -515,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                                    \
@@ -1129,7 +1132,9 @@
 		-proofread $(OUT_DOCS)/$(LOCAL_MODULE)-proofread.txt \
 		-sdkvalues $(OUT_DOCS) \
 		-hdf android.whichdoc offline \
-		-referenceonly
+		-referenceonly \
+		-resourcesdir $(LOCAL_PATH)/docs/html/reference/images/ \
+		-resourcesoutdir reference/android/images/
 
 LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
 
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 59cc432..d158e10 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";
@@ -4824,6 +4835,7 @@
 
   public class KeyguardManager {
     method public android.content.Intent createConfirmDeviceCredentialIntent(java.lang.CharSequence, java.lang.CharSequence);
+    method public void dismissKeyguard(android.app.Activity, android.app.KeyguardManager.KeyguardDismissCallback, android.os.Handler);
     method public deprecated void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
     method public boolean inKeyguardRestrictedInputMode();
     method public boolean isDeviceLocked();
@@ -4833,12 +4845,19 @@
     method public deprecated android.app.KeyguardManager.KeyguardLock newKeyguardLock(java.lang.String);
   }
 
+  public static abstract class KeyguardManager.KeyguardDismissCallback {
+    ctor public KeyguardManager.KeyguardDismissCallback();
+    method public void onDismissCancelled();
+    method public void onDismissError();
+    method public void onDismissSucceeded();
+  }
+
   public deprecated class KeyguardManager.KeyguardLock {
     method public void disableKeyguard();
     method public void reenableKeyguard();
   }
 
-  public static abstract interface KeyguardManager.OnKeyguardExitResult {
+  public static abstract deprecated interface KeyguardManager.OnKeyguardExitResult {
     method public abstract void onKeyguardExitResult(boolean);
   }
 
@@ -5355,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);
@@ -5379,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);
@@ -5413,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);
@@ -5921,6 +5946,13 @@
 
 package android.app.admin {
 
+  public final class ConnectEvent extends android.app.admin.NetworkEvent implements android.os.Parcelable {
+    method public java.lang.String getIpAddress();
+    method public int getPort();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.admin.ConnectEvent> CREATOR;
+  }
+
   public final class DeviceAdminInfo implements android.os.Parcelable {
     ctor public DeviceAdminInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public int describeContents();
@@ -5961,6 +5993,7 @@
     method public void onEnabled(android.content.Context, android.content.Intent);
     method public void onLockTaskModeEntering(android.content.Context, android.content.Intent, java.lang.String);
     method public void onLockTaskModeExiting(android.content.Context, android.content.Intent);
+    method public void onNetworkLogsAvailable(android.content.Context, android.content.Intent, long, int);
     method public void onPasswordChanged(android.content.Context, android.content.Intent);
     method public void onPasswordExpiring(android.content.Context, android.content.Intent);
     method public void onPasswordFailed(android.content.Context, android.content.Intent);
@@ -6005,6 +6038,7 @@
     method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
     method public java.lang.String[] getAccountTypesWithManagementDisabled();
     method public java.util.List<android.content.ComponentName> getActiveAdmins();
+    method public java.util.List<java.lang.String> getAffiliationIds(android.content.ComponentName);
     method public java.lang.String getAlwaysOnVpnPackage(android.content.ComponentName);
     method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
     method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName);
@@ -6064,6 +6098,7 @@
     method public boolean isLockTaskPermitted(java.lang.String);
     method public boolean isManagedProfile(android.content.ComponentName);
     method public boolean isMasterVolumeMuted(android.content.ComponentName);
+    method public boolean isNetworkLoggingEnabled(android.content.ComponentName);
     method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean isProfileOwnerApp(java.lang.String);
     method public boolean isProvisioningAllowed(java.lang.String);
@@ -6077,9 +6112,11 @@
     method public boolean removeUser(android.content.ComponentName, android.os.UserHandle);
     method public boolean requestBugreport(android.content.ComponentName);
     method public boolean resetPassword(java.lang.String, int);
+    method public java.util.List<android.app.admin.NetworkEvent> retrieveNetworkLogs(android.content.ComponentName, long);
     method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(android.content.ComponentName);
     method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(android.content.ComponentName);
     method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
+    method public void setAffiliationIds(android.content.ComponentName, java.util.List<java.lang.String>);
     method public void setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String, boolean) throws android.content.pm.PackageManager.NameNotFoundException, java.lang.UnsupportedOperationException;
     method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
     method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
@@ -6099,6 +6136,7 @@
     method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
+    method public void setNetworkLoggingEnabled(android.content.ComponentName, boolean);
     method public void setOrganizationColor(android.content.ComponentName, int);
     method public void setOrganizationName(android.content.ComponentName, java.lang.CharSequence);
     method public java.lang.String[] setPackagesSuspended(android.content.ComponentName, java.lang.String[], boolean);
@@ -6163,12 +6201,14 @@
     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";
     field public static final java.lang.String EXTRA_PROVISIONING_LOGO_URI = "android.app.extra.PROVISIONING_LOGO_URI";
     field public static final java.lang.String EXTRA_PROVISIONING_MAIN_COLOR = "android.app.extra.PROVISIONING_MAIN_COLOR";
     field public static final java.lang.String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
+    field public static final java.lang.String EXTRA_PROVISIONING_SKIP_USER_CONSENT = "android.app.extra.PROVISIONING_SKIP_USER_CONSENT";
     field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
     field public static final java.lang.String EXTRA_PROVISIONING_WIFI_HIDDEN = "android.app.extra.PROVISIONING_WIFI_HIDDEN";
     field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PAC_URL = "android.app.extra.PROVISIONING_WIFI_PAC_URL";
@@ -6211,6 +6251,22 @@
     field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
   }
 
+  public final class DnsEvent extends android.app.admin.NetworkEvent implements android.os.Parcelable {
+    method public java.lang.String getHostname();
+    method public java.lang.String[] getIpAddresses();
+    method public int getIpAddressesCount();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.admin.DnsEvent> CREATOR;
+  }
+
+  public abstract class NetworkEvent implements android.os.Parcelable {
+    method public int describeContents();
+    method public java.lang.String getPackageName();
+    method public long getTimestamp();
+    method public abstract void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.admin.NetworkEvent> CREATOR;
+  }
+
   public class SecurityLog {
     ctor public SecurityLog();
     field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
@@ -8793,6 +8849,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;
@@ -11991,6 +12048,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);
@@ -12072,6 +12130,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);
@@ -20166,8 +20233,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);
@@ -21451,11 +21518,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;
@@ -21503,6 +21571,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
   }
@@ -25533,7 +25605,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);
@@ -29643,6 +29715,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";
@@ -29998,6 +30071,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();
@@ -30047,6 +30121,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);
@@ -30147,6 +30222,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);
@@ -30186,6 +30276,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();
@@ -30193,6 +30284,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();
@@ -37203,6 +37295,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";
@@ -37391,6 +37484,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;
@@ -44327,7 +44421,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
@@ -64188,7 +64282,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 141f12f..0bfeaf0 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";
@@ -4978,6 +4989,7 @@
 
   public class KeyguardManager {
     method public android.content.Intent createConfirmDeviceCredentialIntent(java.lang.CharSequence, java.lang.CharSequence);
+    method public void dismissKeyguard(android.app.Activity, android.app.KeyguardManager.KeyguardDismissCallback, android.os.Handler);
     method public deprecated void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
     method public boolean inKeyguardRestrictedInputMode();
     method public boolean isDeviceLocked();
@@ -4987,12 +4999,19 @@
     method public deprecated android.app.KeyguardManager.KeyguardLock newKeyguardLock(java.lang.String);
   }
 
+  public static abstract class KeyguardManager.KeyguardDismissCallback {
+    ctor public KeyguardManager.KeyguardDismissCallback();
+    method public void onDismissCancelled();
+    method public void onDismissError();
+    method public void onDismissSucceeded();
+  }
+
   public deprecated class KeyguardManager.KeyguardLock {
     method public void disableKeyguard();
     method public void reenableKeyguard();
   }
 
-  public static abstract interface KeyguardManager.OnKeyguardExitResult {
+  public static abstract deprecated interface KeyguardManager.OnKeyguardExitResult {
     method public abstract void onKeyguardExitResult(boolean);
   }
 
@@ -5511,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);
@@ -5524,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;
@@ -5546,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);
@@ -5580,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);
@@ -6093,6 +6118,13 @@
 
 package android.app.admin {
 
+  public final class ConnectEvent extends android.app.admin.NetworkEvent implements android.os.Parcelable {
+    method public java.lang.String getIpAddress();
+    method public int getPort();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.admin.ConnectEvent> CREATOR;
+  }
+
   public final class DeviceAdminInfo implements android.os.Parcelable {
     ctor public DeviceAdminInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public int describeContents();
@@ -6133,6 +6165,7 @@
     method public void onEnabled(android.content.Context, android.content.Intent);
     method public void onLockTaskModeEntering(android.content.Context, android.content.Intent, java.lang.String);
     method public void onLockTaskModeExiting(android.content.Context, android.content.Intent);
+    method public void onNetworkLogsAvailable(android.content.Context, android.content.Intent, long, int);
     method public void onPasswordChanged(android.content.Context, android.content.Intent);
     method public void onPasswordExpiring(android.content.Context, android.content.Intent);
     method public void onPasswordFailed(android.content.Context, android.content.Intent);
@@ -6177,6 +6210,7 @@
     method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
     method public java.lang.String[] getAccountTypesWithManagementDisabled();
     method public java.util.List<android.content.ComponentName> getActiveAdmins();
+    method public java.util.List<java.lang.String> getAffiliationIds(android.content.ComponentName);
     method public java.lang.String getAlwaysOnVpnPackage(android.content.ComponentName);
     method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
     method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName);
@@ -6194,6 +6228,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);
@@ -6241,10 +6276,12 @@
     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);
     method public boolean isMasterVolumeMuted(android.content.ComponentName);
+    method public boolean isNetworkLoggingEnabled(android.content.ComponentName);
     method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean isProfileOwnerApp(java.lang.String);
     method public boolean isProvisioningAllowed(java.lang.String);
@@ -6259,10 +6296,12 @@
     method public boolean removeUser(android.content.ComponentName, android.os.UserHandle);
     method public boolean requestBugreport(android.content.ComponentName);
     method public boolean resetPassword(java.lang.String, int);
+    method public java.util.List<android.app.admin.NetworkEvent> retrieveNetworkLogs(android.content.ComponentName, long);
     method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(android.content.ComponentName);
     method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(android.content.ComponentName);
     method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
     method public deprecated boolean setActiveProfileOwner(android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException;
+    method public void setAffiliationIds(android.content.ComponentName, java.util.List<java.lang.String>);
     method public void setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String, boolean) throws android.content.pm.PackageManager.NameNotFoundException, java.lang.UnsupportedOperationException;
     method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
     method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
@@ -6282,6 +6321,7 @@
     method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
+    method public void setNetworkLoggingEnabled(android.content.ComponentName, boolean);
     method public void setOrganizationColor(android.content.ComponentName, int);
     method public void setOrganizationName(android.content.ComponentName, java.lang.CharSequence);
     method public java.lang.String[] setPackagesSuspended(android.content.ComponentName, java.lang.String[], boolean);
@@ -6350,12 +6390,14 @@
     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";
     field public static final java.lang.String EXTRA_PROVISIONING_LOGO_URI = "android.app.extra.PROVISIONING_LOGO_URI";
     field public static final java.lang.String EXTRA_PROVISIONING_MAIN_COLOR = "android.app.extra.PROVISIONING_MAIN_COLOR";
     field public static final java.lang.String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
+    field public static final java.lang.String EXTRA_PROVISIONING_SKIP_USER_CONSENT = "android.app.extra.PROVISIONING_SKIP_USER_CONSENT";
     field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
     field public static final java.lang.String EXTRA_PROVISIONING_WIFI_HIDDEN = "android.app.extra.PROVISIONING_WIFI_HIDDEN";
     field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PAC_URL = "android.app.extra.PROVISIONING_WIFI_PAC_URL";
@@ -6403,6 +6445,22 @@
     field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
   }
 
+  public final class DnsEvent extends android.app.admin.NetworkEvent implements android.os.Parcelable {
+    method public java.lang.String getHostname();
+    method public java.lang.String[] getIpAddresses();
+    method public int getIpAddressesCount();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.admin.DnsEvent> CREATOR;
+  }
+
+  public abstract class NetworkEvent implements android.os.Parcelable {
+    method public int describeContents();
+    method public java.lang.String getPackageName();
+    method public long getTimestamp();
+    method public abstract void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.admin.NetworkEvent> CREATOR;
+  }
+
   public class SecurityLog {
     ctor public SecurityLog();
     field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
@@ -9151,6 +9209,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;
@@ -12474,6 +12533,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);
@@ -12555,6 +12615,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);
@@ -21731,8 +21800,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);
@@ -23016,11 +23085,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;
@@ -23068,6 +23138,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
   }
@@ -28058,7 +28132,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);
@@ -32256,6 +32330,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";
@@ -32631,6 +32706,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();
@@ -32680,6 +32756,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);
@@ -32780,6 +32857,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);
@@ -32819,6 +32911,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();
@@ -32827,6 +32920,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();
@@ -35465,6 +35559,7 @@
     field public static final java.lang.String ACTION_DEVICE_INFO_SETTINGS = "android.settings.DEVICE_INFO_SETTINGS";
     field public static final java.lang.String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS";
     field public static final java.lang.String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS";
+    field public static final java.lang.String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
     field public static final java.lang.String ACTION_HARD_KEYBOARD_SETTINGS = "android.settings.HARD_KEYBOARD_SETTINGS";
     field public static final java.lang.String ACTION_HOME_SETTINGS = "android.settings.HOME_SETTINGS";
     field public static final java.lang.String ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS = "android.settings.IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS";
@@ -35579,6 +35674,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";
   }
@@ -37980,19 +38076,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();
@@ -40283,6 +40367,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";
@@ -40471,6 +40556,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;
@@ -47492,7 +47578,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
@@ -67709,7 +67795,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 c9a3579..9cd08d5 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";
@@ -4834,6 +4845,7 @@
 
   public class KeyguardManager {
     method public android.content.Intent createConfirmDeviceCredentialIntent(java.lang.CharSequence, java.lang.CharSequence);
+    method public void dismissKeyguard(android.app.Activity, android.app.KeyguardManager.KeyguardDismissCallback, android.os.Handler);
     method public deprecated void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
     method public boolean inKeyguardRestrictedInputMode();
     method public boolean isDeviceLocked();
@@ -4843,12 +4855,19 @@
     method public deprecated android.app.KeyguardManager.KeyguardLock newKeyguardLock(java.lang.String);
   }
 
+  public static abstract class KeyguardManager.KeyguardDismissCallback {
+    ctor public KeyguardManager.KeyguardDismissCallback();
+    method public void onDismissCancelled();
+    method public void onDismissError();
+    method public void onDismissSucceeded();
+  }
+
   public deprecated class KeyguardManager.KeyguardLock {
     method public void disableKeyguard();
     method public void reenableKeyguard();
   }
 
-  public static abstract interface KeyguardManager.OnKeyguardExitResult {
+  public static abstract deprecated interface KeyguardManager.OnKeyguardExitResult {
     method public abstract void onKeyguardExitResult(boolean);
   }
 
@@ -5365,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);
@@ -5389,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);
@@ -5424,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);
@@ -5938,6 +5963,13 @@
 
 package android.app.admin {
 
+  public final class ConnectEvent extends android.app.admin.NetworkEvent implements android.os.Parcelable {
+    method public java.lang.String getIpAddress();
+    method public int getPort();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.admin.ConnectEvent> CREATOR;
+  }
+
   public final class DeviceAdminInfo implements android.os.Parcelable {
     ctor public DeviceAdminInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public int describeContents();
@@ -5978,6 +6010,7 @@
     method public void onEnabled(android.content.Context, android.content.Intent);
     method public void onLockTaskModeEntering(android.content.Context, android.content.Intent, java.lang.String);
     method public void onLockTaskModeExiting(android.content.Context, android.content.Intent);
+    method public void onNetworkLogsAvailable(android.content.Context, android.content.Intent, long, int);
     method public void onPasswordChanged(android.content.Context, android.content.Intent);
     method public void onPasswordExpiring(android.content.Context, android.content.Intent);
     method public void onPasswordFailed(android.content.Context, android.content.Intent);
@@ -6022,6 +6055,7 @@
     method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
     method public java.lang.String[] getAccountTypesWithManagementDisabled();
     method public java.util.List<android.content.ComponentName> getActiveAdmins();
+    method public java.util.List<java.lang.String> getAffiliationIds(android.content.ComponentName);
     method public java.lang.String getAlwaysOnVpnPackage(android.content.ComponentName);
     method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
     method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName);
@@ -6035,6 +6069,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();
@@ -6080,10 +6115,12 @@
     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);
     method public boolean isMasterVolumeMuted(android.content.ComponentName);
+    method public boolean isNetworkLoggingEnabled(android.content.ComponentName);
     method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean isProfileOwnerApp(java.lang.String);
     method public boolean isProvisioningAllowed(java.lang.String);
@@ -6097,9 +6134,11 @@
     method public boolean removeUser(android.content.ComponentName, android.os.UserHandle);
     method public boolean requestBugreport(android.content.ComponentName);
     method public boolean resetPassword(java.lang.String, int);
+    method public java.util.List<android.app.admin.NetworkEvent> retrieveNetworkLogs(android.content.ComponentName, long);
     method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(android.content.ComponentName);
     method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(android.content.ComponentName);
     method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
+    method public void setAffiliationIds(android.content.ComponentName, java.util.List<java.lang.String>);
     method public void setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String, boolean) throws android.content.pm.PackageManager.NameNotFoundException, java.lang.UnsupportedOperationException;
     method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
     method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
@@ -6119,6 +6158,7 @@
     method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
+    method public void setNetworkLoggingEnabled(android.content.ComponentName, boolean);
     method public void setOrganizationColor(android.content.ComponentName, int);
     method public void setOrganizationName(android.content.ComponentName, java.lang.CharSequence);
     method public java.lang.String[] setPackagesSuspended(android.content.ComponentName, java.lang.String[], boolean);
@@ -6183,12 +6223,14 @@
     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";
     field public static final java.lang.String EXTRA_PROVISIONING_LOGO_URI = "android.app.extra.PROVISIONING_LOGO_URI";
     field public static final java.lang.String EXTRA_PROVISIONING_MAIN_COLOR = "android.app.extra.PROVISIONING_MAIN_COLOR";
     field public static final java.lang.String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
+    field public static final java.lang.String EXTRA_PROVISIONING_SKIP_USER_CONSENT = "android.app.extra.PROVISIONING_SKIP_USER_CONSENT";
     field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
     field public static final java.lang.String EXTRA_PROVISIONING_WIFI_HIDDEN = "android.app.extra.PROVISIONING_WIFI_HIDDEN";
     field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PAC_URL = "android.app.extra.PROVISIONING_WIFI_PAC_URL";
@@ -6231,6 +6273,22 @@
     field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
   }
 
+  public final class DnsEvent extends android.app.admin.NetworkEvent implements android.os.Parcelable {
+    method public java.lang.String getHostname();
+    method public java.lang.String[] getIpAddresses();
+    method public int getIpAddressesCount();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.admin.DnsEvent> CREATOR;
+  }
+
+  public abstract class NetworkEvent implements android.os.Parcelable {
+    method public int describeContents();
+    method public java.lang.String getPackageName();
+    method public long getTimestamp();
+    method public abstract void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.admin.NetworkEvent> CREATOR;
+  }
+
   public class SecurityLog {
     ctor public SecurityLog();
     field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
@@ -8816,6 +8874,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;
@@ -12020,6 +12079,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);
@@ -12101,6 +12161,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);
@@ -20251,8 +20320,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);
@@ -21536,11 +21605,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;
@@ -21588,6 +21658,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
   }
@@ -25618,7 +25692,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);
@@ -29730,6 +29804,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";
@@ -30085,6 +30160,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();
@@ -30134,6 +30210,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);
@@ -30234,6 +30311,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);
@@ -30273,6 +30365,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();
@@ -30280,6 +30373,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();
@@ -32764,6 +32858,7 @@
     field public static final java.lang.String ACTION_DEVICE_INFO_SETTINGS = "android.settings.DEVICE_INFO_SETTINGS";
     field public static final java.lang.String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS";
     field public static final java.lang.String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS";
+    field public static final java.lang.String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
     field public static final java.lang.String ACTION_HARD_KEYBOARD_SETTINGS = "android.settings.HARD_KEYBOARD_SETTINGS";
     field public static final java.lang.String ACTION_HOME_SETTINGS = "android.settings.HOME_SETTINGS";
     field public static final java.lang.String ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS = "android.settings.IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS";
@@ -37297,6 +37392,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";
@@ -37485,6 +37581,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;
@@ -44581,7 +44678,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
@@ -64458,7 +64555,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/cmds/wm/src/com/android/commands/wm/Wm.java b/cmds/wm/src/com/android/commands/wm/Wm.java
index 84fb626..8defb33 100644
--- a/cmds/wm/src/com/android/commands/wm/Wm.java
+++ b/cmds/wm/src/com/android/commands/wm/Wm.java
@@ -274,7 +274,7 @@
     }
 
     private void runDismissKeyguard() throws Exception {
-        mWm.dismissKeyguard();
+        mWm.dismissKeyguard(null /* callback */);
     }
 
     private int parseDimension(String s) throws NumberFormatException {
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/Activity.java b/core/java/android/app/Activity.java
index 90fff8d..eb73e36 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3044,8 +3044,11 @@
      * @hide
      */
     @Override
-    public void onWindowDismissed(boolean finishTask) {
+    public void onWindowDismissed(boolean finishTask, boolean suppressWindowTransition) {
         finish(finishTask ? FINISH_TASK_WITH_ACTIVITY : DONT_FINISH_TASK_WITH_ACTIVITY);
+        if (suppressWindowTransition) {
+            overridePendingTransition(0, 0);
+        }
     }
 
 
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/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index abb098f..84adbe5 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -349,9 +351,17 @@
 
     public BackStackRecord(FragmentManagerImpl manager) {
         mManager = manager;
-        int targetSdkVersion = manager.mHost.getContext().getApplicationInfo().targetSdkVersion;
-        // TODO: make the check N_MR1 or O
-        mAllowOptimization = targetSdkVersion > Build.VERSION_CODES.N;
+        FragmentHostCallback host = manager.mHost;
+        if (host != null) {
+            Context context = host.getContext();
+            if (context != null) {
+                ApplicationInfo info = context.getApplicationInfo();
+                if (info != null) {
+                    int targetSdkVersion = info.targetSdkVersion;
+                    mAllowOptimization = targetSdkVersion > Build.VERSION_CODES.N_MR1;
+                }
+            }
+        }
     }
 
     public int getId() {
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..9c17780 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);
     }
 
@@ -742,7 +744,7 @@
 
     /** @hide */
     @Override
-    public void onWindowDismissed(boolean finishTask) {
+    public void onWindowDismissed(boolean finishTask, boolean suppressWindowTransition) {
         dismiss();
     }
 
@@ -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 3464c4d..10d584f 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -19,6 +19,8 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.app.SharedElementCallback.OnSharedElementsReadyListener;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.ResultReceiver;
@@ -61,6 +63,7 @@
     private Transition mEnterViewsTransition;
     private OneShotPreDrawListener mViewsReadyListener;
     private final boolean mIsCrossTask;
+    private Drawable mReplacedBackground;
 
     public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver,
             ArrayList<String> sharedElementNames, boolean isReturning, boolean isCrossTask) {
@@ -87,7 +90,7 @@
                                     decorView.getViewTreeObserver().removeOnPreDrawListener(this);
                                 }
                             }
-                            return mIsReadyForTransition;
+                            return false;
                         }
                     });
         }
@@ -332,12 +335,15 @@
         if (!mIsReturning) {
             mWasOpaque = mActivity.convertToTranslucent(null, null);
             Drawable background = decorView.getBackground();
-            if (background != null) {
+            if (background == null) {
+                background = new ColorDrawable(Color.TRANSPARENT);
+                mReplacedBackground = background;
+            } else {
                 getWindow().setBackgroundDrawable(null);
                 background = background.mutate();
                 background.setAlpha(0);
-                getWindow().setBackgroundDrawable(background);
             }
+            getWindow().setBackgroundDrawable(background);
         } else {
             mActivity = null; // all done with it now.
         }
@@ -553,6 +559,11 @@
         final ViewGroup decorView = getDecor();
         if (decorView != null) {
             decorView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+
+            Window window = getWindow();
+            if (window != null && mReplacedBackground == decorView.getBackground()) {
+                window.setBackgroundDrawable(null);
+            }
         }
     }
 
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index 6a79e6c..21e3aee 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -236,7 +236,7 @@
             delayCancel();
             moveSharedElementsToOverlay();
             if (decorView != null && decorView.getBackground() == null) {
-                getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK));
+                getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
             }
             final boolean targetsM = decorView == null || decorView.getContext()
                     .getApplicationInfo().targetSdkVersion >= VERSION_CODES.M;
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 82be7ab..640ca6c 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -31,6 +31,7 @@
 import android.app.ITaskStackListener;
 import android.app.IUiAutomationConnection;
 import android.app.IUidObserver;
+
 import android.app.IUserSwitchObserver;
 import android.app.Notification;
 import android.app.PendingIntent;
@@ -65,6 +66,7 @@
 import android.service.voice.IVoiceInteractionSession;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.os.IResultReceiver;
+import com.android.internal.policy.IKeyguardDismissCallback;
 
 import java.util.List;
 
@@ -368,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();
@@ -571,6 +572,7 @@
     void setPictureInPictureAspectRatio(in IBinder token, float aspectRatio);
     boolean requestAutoFillData(in IResultReceiver receiver, in Bundle receiverExtras,
             in IBinder activityToken);
+    void dismissKeyguard(in IBinder token, in IKeyguardDismissCallback callback);
 
     // WARNING: when these transactions are updated, check if they are any callers on the native
     // side. If so, make sure they are using the correct transaction ids.
diff --git a/core/java/android/app/IInstrumentationWatcher.aidl b/core/java/android/app/IInstrumentationWatcher.aidl
index 405a3d8..6c8c4d6 100644
--- a/core/java/android/app/IInstrumentationWatcher.aidl
+++ b/core/java/android/app/IInstrumentationWatcher.aidl
@@ -21,7 +21,7 @@
 import android.os.Bundle;
 
 /** @hide */
-oneway interface IInstrumentationWatcher
+interface IInstrumentationWatcher
 {
     void instrumentationStatus(in ComponentName name, int resultCode,
             in Bundle results);
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/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 725cc29..036b47c 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -17,24 +17,32 @@
 package android.app;
 
 import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.app.trust.ITrustManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
 import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.IBinder;
 import android.os.IUserManager;
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
 import android.os.UserHandle;
-import android.os.UserManager;
+import android.util.Log;
 import android.view.IWindowManager;
 import android.view.IOnKeyguardExitResult;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
 import android.view.WindowManagerGlobal;
 
+import com.android.internal.policy.IKeyguardDismissCallback;
+
 /**
  * Class that can be used to lock and unlock the keyboard. Get an instance of this
  * class by calling {@link android.content.Context#getSystemService(java.lang.String)}
@@ -43,10 +51,13 @@
  * {@link android.app.KeyguardManager.KeyguardLock}.
  */
 public class KeyguardManager {
-    private IWindowManager mWM;
-    private ITrustManager mTrustManager;
-    private IUserManager mUserManager;
-    private Context mContext;
+
+    private static final String TAG = "KeyguardManager";
+
+    private final Context mContext;
+    private final IWindowManager mWM;
+    private final IActivityManager mAm;
+    private final ITrustManager mTrustManager;
 
     /**
      * Intent used to prompt user for device credentials.
@@ -125,8 +136,8 @@
     }
 
     /**
-     * @deprecated Use {@link android.view.WindowManager.LayoutParams#FLAG_DISMISS_KEYGUARD}
-     * and/or {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED}
+     * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD}
+     * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED}
      * instead; this allows you to seamlessly hide the keyguard as your application
      * moves in and out of the foreground and does not require that any special
      * permissions be requested.
@@ -190,9 +201,11 @@
     }
 
     /**
+     * @deprecated Use {@link KeyguardDismissCallback}
      * Callback passed to {@link KeyguardManager#exitKeyguardSecurely} to notify
      * caller of result.
      */
+    @Deprecated
     public interface OnKeyguardExitResult {
 
         /**
@@ -202,19 +215,41 @@
         void onKeyguardExitResult(boolean success);
     }
 
+    /**
+     * Callback passed to {@link KeyguardManager#dismissKeyguard} to notify caller of result.
+     */
+    public static abstract class KeyguardDismissCallback {
+
+        /**
+         * Called when dismissing Keyguard is currently not feasible, i.e. when Keyguard is not
+         * available, not showing or when the activity requesting the Keyguard dismissal isn't
+         * showing or isn't showing behind Keyguard.
+         */
+        public void onDismissError() { }
+
+        /**
+         * Called when dismissing Keyguard has succeeded and the device is now unlocked.
+         */
+        public void onDismissSucceeded() { }
+
+        /**
+         * Called when dismissing Keyguard has been cancelled, i.e. when the user cancelled the
+         * operation or the bouncer was hidden for some other reason.
+         */
+        public void onDismissCancelled() { }
+    }
 
     KeyguardManager(Context context) throws ServiceNotFoundException {
         mContext = context;
         mWM = WindowManagerGlobal.getWindowManagerService();
+        mAm = ActivityManager.getService();
         mTrustManager = ITrustManager.Stub.asInterface(
                 ServiceManager.getServiceOrThrow(Context.TRUST_SERVICE));
-        mUserManager = IUserManager.Stub.asInterface(
-                ServiceManager.getServiceOrThrow(Context.USER_SERVICE));
     }
 
     /**
-     * @deprecated Use {@link android.view.WindowManager.LayoutParams#FLAG_DISMISS_KEYGUARD}
-     * and/or {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED}
+     * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD}
+     * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED}
      * instead; this allows you to seamlessly hide the keyguard as your application
      * moves in and out of the foreground and does not require that any special
      * permissions be requested.
@@ -296,9 +331,8 @@
      * @hide
      */
     public boolean isDeviceLocked(int userId) {
-        ITrustManager trustManager = getTrustManager();
         try {
-            return trustManager.isDeviceLocked(userId);
+            return mTrustManager.isDeviceLocked(userId);
         } catch (RemoteException e) {
             return false;
         }
@@ -322,25 +356,63 @@
      * @hide
      */
     public boolean isDeviceSecure(int userId) {
-        ITrustManager trustManager = getTrustManager();
         try {
-            return trustManager.isDeviceSecure(userId);
+            return mTrustManager.isDeviceSecure(userId);
         } catch (RemoteException e) {
             return false;
         }
     }
 
-    private synchronized ITrustManager getTrustManager() {
-        if (mTrustManager == null) {
-            mTrustManager = ITrustManager.Stub.asInterface(
-                    ServiceManager.getService(Context.TRUST_SERVICE));
+    /**
+     * If the device is currently locked (see {@link #isKeyguardLocked()}, requests the Keyguard to
+     * be dismissed.
+     * <p>
+     * If the Keyguard is not secure or the device is currently in a trusted state, calling this
+     * method will immediately dismiss the Keyguard without any user interaction.
+     * <p>
+     * If the Keyguard is secure and the device is not in a trusted state, this will bring up the
+     * UI so the user can enter their credentials.
+     *
+     * @param activity The activity requesting the dismissal. The activity must be either visible
+     *                 by using {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} or must be in a state in
+     *                 which it would be visible if Keyguard would not be hiding it. If that's not
+     *                 the case, the request will fail immediately and
+     *                 {@link KeyguardDismissCallback#onDismissError} will be invoked.
+     * @param callback The callback to be called if the request to dismiss Keyguard was successful
+     *                 or {@code null} if the caller isn't interested in knowing the result.
+     * @param handler The handler to invoke the callback on, or {@code null} to use the main
+     *                handler.
+     */
+    public void dismissKeyguard(@NonNull Activity activity,
+            @Nullable KeyguardDismissCallback callback, @Nullable Handler handler) {
+        try {
+            final Handler actualHandler = handler != null
+                    ? handler
+                    : new Handler(Looper.getMainLooper());
+            mAm.dismissKeyguard(activity.getActivityToken(), new IKeyguardDismissCallback.Stub() {
+                @Override
+                public void onDismissError() throws RemoteException {
+                    actualHandler.post(callback::onDismissError);
+                }
+
+                @Override
+                public void onDismissSucceeded() throws RemoteException {
+                    actualHandler.post(callback::onDismissSucceeded);
+                }
+
+                @Override
+                public void onDismissCancelled() throws RemoteException {
+                    actualHandler.post(callback::onDismissCancelled);
+                }
+            });
+        } catch (RemoteException e) {
+            Log.i(TAG, "Failed to dismiss keyguard: " + e);
         }
-        return mTrustManager;
     }
 
     /**
-     * @deprecated Use {@link android.view.WindowManager.LayoutParams#FLAG_DISMISS_KEYGUARD}
-     * and/or {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED}
+     * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD}
+     * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED}
      * instead; this allows you to seamlessly hide the keyguard as your application
      * moves in and out of the foreground and does not require that any special
      * permissions be requested.
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 e05feaf..5111443 100644
--- a/core/java/android/app/admin/ConnectEvent.java
+++ b/core/java/android/app/admin/ConnectEvent.java
@@ -21,7 +21,6 @@
 
 /**
  * A class that represents a connect library call event.
- * @hide
  */
 public final class ConnectEvent extends NetworkEvent implements Parcelable {
 
@@ -31,6 +30,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;
@@ -75,6 +75,11 @@
     };
 
     @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
     public void writeToParcel(Parcel out, int flags) {
         // write parcel token first
         out.writeInt(PARCEL_TOKEN_CONNECT_EVENT);
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index b1eca5c..aae80ed 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -702,8 +702,6 @@
      * @param batchToken The token representing the current batch of network logs.
      * @param networkLogsCount The total count of events in the current batch of network logs.
      * @see DevicePolicyManager#retrieveNetworkLogs(ComponentName)
-     *
-     * @hide
      */
     public void onNetworkLogsAvailable(Context context, Intent intent, long batchToken,
             int networkLogsCount) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e0ec1b1..85d202c 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -79,7 +79,6 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-import java.util.Set;
 
 /**
  * Public interface for managing policies enforced on a device. Most clients of this class must be
@@ -151,6 +150,8 @@
      * <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}, optional</li>
      * <li>{@link #EXTRA_PROVISIONING_LOGO_URI}, optional</li>
      * <li>{@link #EXTRA_PROVISIONING_MAIN_COLOR}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_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
@@ -813,6 +832,16 @@
             "android.app.extra.PROVISIONING_SKIP_USER_SETUP";
 
     /**
+     * A boolean extra indicating if the user consent steps from the provisioning flow should be
+     * skipped. If unspecified, defaults to {@code false}.
+     *
+     * It can only be used by an existing device owner trying to create a managed profile via
+     * {@link #ACTION_PROVISION_MANAGED_PROFILE}. Otherwise it is ignored.
+     */
+    public static final String EXTRA_PROVISIONING_SKIP_USER_CONSENT =
+            "android.app.extra.PROVISIONING_SKIP_USER_CONSENT";
+
+    /**
      * This MIME type is used for starting the device owner provisioning.
      *
      * <p>During device owner provisioning a device admin app is set as the owner of the device.
@@ -1080,6 +1109,172 @@
     public @interface UserProvisioningState {}
 
     /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_DEVICE},
+     * {@link #ACTION_PROVISION_MANAGED_PROFILE}, {@link #ACTION_PROVISION_MANAGED_USER} and
+     * {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE} when provisioning is allowed.
+     *
+     * @hide
+     */
+    public static final int CODE_OK = 0;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_DEVICE} and
+     * {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE} when the device already has a device
+     * owner.
+     *
+     * @hide
+     */
+    public static final int CODE_HAS_DEVICE_OWNER = 1;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_DEVICE},
+     * {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE} when the user has a profile owner and for
+     * {@link #ACTION_PROVISION_MANAGED_PROFILE} when the profile owner is already set.
+     *
+     * @hide
+     */
+    public static final int CODE_USER_HAS_PROFILE_OWNER = 2;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_DEVICE} and
+     * {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE} when the user isn't running.
+     *
+     * @hide
+     */
+    public static final int CODE_USER_NOT_RUNNING = 3;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_DEVICE},
+     * {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE} if the device has already been setup and
+     * for {@link #ACTION_PROVISION_MANAGED_USER} if the user has already been setup.
+     *
+     * @hide
+     */
+    public static final int CODE_USER_SETUP_COMPLETED = 4;
+
+    /**
+     * Code used to indicate that the device also has a user other than the system user.
+     *
+     * @hide
+     */
+    public static final int CODE_NONSYSTEM_USER_EXISTS = 5;
+
+    /**
+     * Code used to indicate that device has an account that prevents provisioning.
+     *
+     * @hide
+     */
+    public static final int CODE_ACCOUNTS_NOT_EMPTY = 6;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_DEVICE} and
+     * {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE} if the user is not a system user.
+     *
+     * @hide
+     */
+    public static final int CODE_NOT_SYSTEM_USER = 7;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_DEVICE},
+     * {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE} and {@link #ACTION_PROVISION_MANAGED_USER}
+     * when the device is a watch and is already paired.
+     *
+     * @hide
+     */
+    public static final int CODE_HAS_PAIRED = 8;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_PROFILE} and
+     * {@link #ACTION_PROVISION_MANAGED_USER} on devices which do not support managed users.
+     *
+     * @see {@link PackageManager#FEATURE_MANAGED_USERS}
+     * @hide
+     */
+    public static final int CODE_MANAGED_USERS_NOT_SUPPORTED = 9;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_USER} if the user is a system user.
+     *
+     * @hide
+     */
+    public static final int CODE_SYSTEM_USER = 10;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_PROFILE} when the user cannot have more
+     * managed profiles.
+     *
+     * @hide
+     */
+    public static final int CODE_CANNOT_ADD_MANAGED_PROFILE = 11;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_USER} and
+     * {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE} on devices not running with split system
+     * user.
+     *
+     * @hide
+     */
+    public static final int CODE_NOT_SYSTEM_USER_SPLIT = 12;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_DEVICE},
+     * {@link #ACTION_PROVISION_MANAGED_PROFILE}, {@link #ACTION_PROVISION_MANAGED_USER} and
+     * {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE} on devices which do no support device
+     * admins.
+     *
+     * @hide
+     */
+    public static final int CODE_DEVICE_ADMIN_NOT_SUPPORTED = 13;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_PROFILE} when the device has a device owner
+     * and the user is a system user on a split system user device.
+     *
+     * @hide
+     */
+    public static final int CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER = 14;
+
+    /**
+     * Result codes for {@link checkProvisioningPreCondition} indicating all the provisioning pre
+     * conditions.
+     *
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({CODE_OK, CODE_HAS_DEVICE_OWNER, CODE_USER_HAS_PROFILE_OWNER, CODE_USER_NOT_RUNNING,
+            CODE_USER_SETUP_COMPLETED, CODE_NOT_SYSTEM_USER, CODE_HAS_PAIRED,
+            CODE_MANAGED_USERS_NOT_SUPPORTED, CODE_SYSTEM_USER, CODE_CANNOT_ADD_MANAGED_PROFILE,
+            CODE_NOT_SYSTEM_USER_SPLIT, CODE_DEVICE_ADMIN_NOT_SUPPORTED,
+            CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER})
+    public @interface ProvisioningPreCondition {}
+
+    /**
      * Return true if the given administrator component is currently active (enabled) in the system.
      *
      * @param admin The administrator component to check for.
@@ -3834,14 +4029,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();
+        }
     }
 
     /**
@@ -5941,6 +6144,24 @@
     }
 
     /**
+     * Checks if provisioning a managed profile or device is possible and returns one of the
+     * {@link ProvisioningPreCondition}.
+     *
+     * @param action One of {@link #ACTION_PROVISION_MANAGED_DEVICE},
+     *        {@link #ACTION_PROVISION_MANAGED_PROFILE},
+     *        {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE},
+     *        {@link #ACTION_PROVISION_MANAGED_USER}
+     * @hide
+     */
+    public @ProvisioningPreCondition int checkProvisioningPreCondition(String action) {
+        try {
+            return mService.checkProvisioningPreCondition(action);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Return if this user is a managed profile of another user. An admin can become the profile
      * owner of a managed profile with {@link #ACTION_PROVISION_MANAGED_PROFILE} and of a managed
      * user with {@link #createAndManageUser}
@@ -6401,7 +6622,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
@@ -6410,7 +6631,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");
@@ -6439,6 +6660,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.
@@ -6491,27 +6731,32 @@
     }
 
     /**
-     * @hide
-     * Indicates the entity that controls the device or profile owner. A user/profile is considered
-     * affiliated if it is managed by the same entity as the device.
-     *
-     * <p> By definition, the user that the device owner runs on is always affiliated. Any other
-     * user/profile is considered affiliated if the following conditions are both met:
-     * <ul>
-     * <li>The device owner and the user's/profile's profile owner have called this method,
-     *   specifying a set of opaque affiliation ids each. If the sets specified by the device owner
-     *   and a profile owner intersect, they must have come from the same source, which means that
-     *   the device owner and profile owner are controlled by the same entity.</li>
-     * <li>The device owner's and profile owner's package names are the same.</li>
-     * </ul>
+     * Indicates the entity that controls the device or profile owner. Two users/profiles are
+     * affiliated if the set of ids set by their device or profile owners intersect.
      *
      * @param admin Which profile or device owner this request is associated with.
-     * @param ids A set of opaque affiliation ids.
+     * @param ids A list of opaque non-empty affiliation ids. Duplicate elements will be ignored.
+     *
+     * @throws NullPointerException if {@code ids} is null or contains null elements.
+     * @throws IllegalArgumentException if {@code ids} contains an empty string.
      */
-    public void setAffiliationIds(@NonNull ComponentName admin, Set<String> ids) {
+    public void setAffiliationIds(@NonNull ComponentName admin, @NonNull List<String> ids) {
         throwIfParentInstance("setAffiliationIds");
         try {
-            mService.setAffiliationIds(admin, new ArrayList<String>(ids));
+            mService.setAffiliationIds(admin, ids);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns the list of affiliation ids previously set via {@link #setAffiliationIds}, or an
+     * empty list if none have been set.
+     */
+    public @NonNull List<String> getAffiliationIds(@NonNull ComponentName admin) {
+        throwIfParentInstance("getAffiliationIds");
+        try {
+            return mService.getAffiliationIds(admin);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -6519,15 +6764,17 @@
 
     /**
      * @hide
-     * Returns whether this user/profile is affiliated with the device. See
-     * {@link #setAffiliationIds} for the definition of affiliation.
+     * Returns whether this user/profile is affiliated with the device.
+     * <p>
+     * By definition, the user that the device owner runs on is always affiliated with the device.
+     * Any other user/profile is considered affiliated with the device if the set specified by its
+     * profile owner via {@link #setAffiliationIds} intersects with the device owner's.
      *
-     * @return whether this user/profile is affiliated with the device.
      */
     public boolean isAffiliatedUser() {
         throwIfParentInstance("isAffiliatedUser");
         try {
-            return mService != null && mService.isAffiliatedUser();
+            return mService.isAffiliatedUser();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -6678,8 +6925,6 @@
      * @param enabled whether network logging should be enabled or not.
      * @throws {@link SecurityException} if {@code admin} is not a device owner.
      * @see #retrieveNetworkLogs
-     *
-     * @hide
      */
     public void setNetworkLoggingEnabled(@NonNull ComponentName admin, boolean enabled) {
         throwIfParentInstance("setNetworkLoggingEnabled");
@@ -6696,8 +6941,6 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @return {@code true} if network logging is enabled by device owner, {@code false} otherwise.
      * @throws {@link SecurityException} if {@code admin} is not a device owner.
-     *
-     * @hide
      */
     public boolean isNetworkLoggingEnabled(@NonNull ComponentName admin) {
         throwIfParentInstance("isNetworkLoggingEnabled");
@@ -6729,8 +6972,6 @@
      *        logging is disabled.
      * @throws {@link SecurityException} if {@code admin} is not a device owner.
      * @see DeviceAdminReceiver#onNetworkLogsAvailable
-     *
-     * @hide
      */
     public @Nullable List<NetworkEvent> retrieveNetworkLogs(@NonNull ComponentName admin,
             long batchToken) {
diff --git a/core/java/android/app/admin/DnsEvent.java b/core/java/android/app/admin/DnsEvent.java
index 0ec134a..a3a3f58 100644
--- a/core/java/android/app/admin/DnsEvent.java
+++ b/core/java/android/app/admin/DnsEvent.java
@@ -21,7 +21,6 @@
 
 /**
  * A class that represents a DNS lookup event.
- * @hide
  */
 public final class DnsEvent extends NetworkEvent implements Parcelable {
 
@@ -37,6 +36,7 @@
      */
     private final int ipAddressesCount;
 
+    /** @hide */
     public DnsEvent(String hostname, String[] ipAddresses, int ipAddressesCount,
             String packageName, long timestamp) {
         super(packageName, timestamp);
@@ -95,6 +95,11 @@
     };
 
     @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
     public void writeToParcel(Parcel out, int flags) {
         // write parcel token first
         out.writeInt(PARCEL_TOKEN_DNS_EVENT);
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index b7e0e92..3e22825 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();
@@ -269,6 +270,7 @@
             String permission, int grantState);
     int getPermissionGrantState(in ComponentName admin, String packageName, String permission);
     boolean isProvisioningAllowed(String action);
+    int checkProvisioningPreCondition(String action);
     void setKeepUninstalledPackages(in ComponentName admin,in List<String> packageList);
     List<String> getKeepUninstalledPackages(in ComponentName admin);
     boolean isManagedProfile(in ComponentName admin);
@@ -293,12 +295,14 @@
 
     void setOrganizationName(in ComponentName admin, in CharSequence title);
     CharSequence getOrganizationName(in ComponentName admin);
+    CharSequence getDeviceOwnerOrganizationName();
     CharSequence getOrganizationNameForUser(int userHandle);
 
     int getUserProvisioningState();
     void setUserProvisioningState(int state, int userHandle);
 
     void setAffiliationIds(in ComponentName admin, in List<String> ids);
+    List<String> getAffiliationIds(in ComponentName admin);
     boolean isAffiliatedUser();
 
     void setSecurityLoggingEnabled(in ComponentName admin, boolean enabled);
diff --git a/core/java/android/app/admin/NetworkEvent.java b/core/java/android/app/admin/NetworkEvent.java
index ec7ed00..2646c3f 100644
--- a/core/java/android/app/admin/NetworkEvent.java
+++ b/core/java/android/app/admin/NetworkEvent.java
@@ -16,40 +16,50 @@
 
 package android.app.admin;
 
+import android.content.pm.PackageManager;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.ParcelFormatException;
 
 /**
  * An abstract class that represents a network event.
- * @hide
  */
 public abstract class NetworkEvent implements Parcelable {
 
-    protected static final int PARCEL_TOKEN_DNS_EVENT = 1;
-    protected static final int PARCEL_TOKEN_CONNECT_EVENT = 2;
+    /** @hide */
+    static final int PARCEL_TOKEN_DNS_EVENT = 1;
+    /** @hide */
+    static final int PARCEL_TOKEN_CONNECT_EVENT = 2;
 
     /** The package name of the UID that performed the query. */
-    protected String packageName;
+    String packageName;
 
     /** The timestamp of the event being reported in milliseconds. */
-    protected long timestamp;
+    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;
     }
@@ -81,5 +91,8 @@
             return new NetworkEvent[size];
         }
     };
+
+    @Override
+    public abstract void writeToParcel(Parcel out, int flags);
 }
 
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..f5eb4bd 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -17,6 +17,7 @@
 package android.content.pm;
 
 import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.XmlUtils;
 
@@ -39,6 +40,9 @@
 import android.os.PatternMatcher;
 import android.os.Trace;
 import android.os.UserHandle;
+import android.system.ErrnoException;
+import android.system.OsConstants;
+import android.system.StructStat;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -54,6 +58,8 @@
 import android.view.Gravity;
 
 import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
@@ -259,6 +265,7 @@
     private String[] mSeparateProcesses;
     private boolean mOnlyCoreApps;
     private DisplayMetrics mMetrics;
+    private File mCacheDir;
 
     private static final int SDK_VERSION = Build.VERSION.SDK_INT;
     private static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
@@ -453,6 +460,13 @@
         mMetrics = metrics;
     }
 
+    /**
+     * Sets the cache directory for this package parser.
+     */
+    public void setCacheDir(File cacheDir) {
+        mCacheDir = cacheDir;
+    }
+
     public static final boolean isApkFile(File file) {
         return isApkPath(file.getName());
     }
@@ -478,20 +492,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();
@@ -801,13 +820,154 @@
      * Note that this <em>does not</em> perform signature verification; that
      * must be done separately in {@link #collectCertificates(Package, int)}.
      *
+     * If {@code useCaches} is true, the package parser might return a cached
+     * result from a previous parse of the same {@code packageFile} with the same
+     * {@code flags}. Note that this method does not check whether {@code packageFile}
+     * has changed since the last parse, it's up to callers to do so.
+     *
      * @see #parsePackageLite(File, int)
      */
-    public Package parsePackage(File packageFile, int flags) throws PackageParserException {
+    public Package parsePackage(File packageFile, int flags, boolean useCaches)
+            throws PackageParserException {
+        Package parsed = useCaches ? getCachedResult(packageFile, flags) : null;
+        if (parsed != null) {
+            return parsed;
+        }
+
         if (packageFile.isDirectory()) {
-            return parseClusterPackage(packageFile, flags);
+            parsed = parseClusterPackage(packageFile, flags);
         } else {
-            return parseMonolithicPackage(packageFile, flags);
+            parsed = parseMonolithicPackage(packageFile, flags);
+        }
+
+        cacheResult(packageFile, flags, parsed);
+
+        return parsed;
+    }
+
+    /**
+     * Equivalent to {@link #parsePackage(File, int, boolean)} with {@code useCaches == false}.
+     */
+    public Package parsePackage(File packageFile, int flags) throws PackageParserException {
+        return parsePackage(packageFile, flags, false /* useCaches */);
+    }
+
+    /**
+     * Returns the cache key for a specificied {@code packageFile} and {@code flags}.
+     */
+    private String getCacheKey(File packageFile, int flags) {
+        StringBuilder sb = new StringBuilder(packageFile.getName());
+        sb.append('-');
+        sb.append(flags);
+
+        return sb.toString();
+    }
+
+    @VisibleForTesting
+    protected Package fromCacheEntry(byte[] bytes) throws IOException {
+        return null;
+    }
+
+    @VisibleForTesting
+    protected byte[] toCacheEntry(Package pkg) throws IOException {
+        return null;
+    }
+
+    /**
+     * Given a {@code packageFile} and a {@code cacheFile} returns whether the
+     * cache file is up to date based on the mod-time of both files.
+     */
+    private static boolean isCacheUpToDate(File packageFile, File cacheFile) {
+        try {
+            // NOTE: We don't use the File.lastModified API because it has the very
+            // non-ideal failure mode of returning 0 with no excepions thrown.
+            // The nio2 Files API is a little better but is considerably more expensive.
+            final StructStat pkg = android.system.Os.stat(packageFile.getAbsolutePath());
+            final StructStat cache = android.system.Os.stat(cacheFile.getAbsolutePath());
+            return pkg.st_mtime < cache.st_mtime;
+        } catch (ErrnoException ee) {
+            // The most common reason why stat fails is that a given cache file doesn't
+            // exist. We ignore that here. It's easy to reason that it's safe to say the
+            // cache isn't up to date if we see any sort of exception here.
+            //
+            // (1) Exception while stating the package file : This should never happen,
+            // and if it does, we do a full package parse (which is likely to throw the
+            // same exception).
+            // (2) Exception while stating the cache file : If the file doesn't exist, the
+            // cache is obviously out of date. If the file *does* exist, we can't read it.
+            // We will attempt to delete and recreate it after parsing the package.
+            if (ee.errno != OsConstants.ENOENT) {
+                Slog.w("Error while stating package cache : ", ee);
+            }
+
+            return false;
+        }
+    }
+
+    /**
+     * Returns the cached parse result for {@code packageFile} for parse flags {@code flags},
+     * or {@code null} if no cached result exists.
+     */
+    private Package getCachedResult(File packageFile, int flags) {
+        if (mCacheDir == null) {
+            return null;
+        }
+
+        final String cacheKey = getCacheKey(packageFile, flags);
+        final File cacheFile = new File(mCacheDir, cacheKey);
+
+        // If the cache is not up to date, return null.
+        if (!isCacheUpToDate(packageFile, cacheFile)) {
+            return null;
+        }
+
+        try {
+            final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath());
+            return fromCacheEntry(bytes);
+        } catch (IOException ioe) {
+            Slog.w(TAG, "Error reading package cache: ", ioe);
+
+            // If something went wrong while reading the cache entry, delete the cache file
+            // so that we regenerate it the next time.
+            cacheFile.delete();
+            return null;
+        }
+    }
+
+    /**
+     * Caches the parse result for {@code packageFile} with flags {@code flags}.
+     */
+    private void cacheResult(File packageFile, int flags, Package parsed) {
+        if (mCacheDir == null) {
+            return;
+        }
+
+        final String cacheKey = getCacheKey(packageFile, flags);
+        final File cacheFile = new File(mCacheDir, cacheKey);
+
+        if (cacheFile.exists()) {
+            if (!cacheFile.delete()) {
+                Slog.e(TAG, "Unable to delete cache file: " + cacheFile);
+            }
+        }
+
+        final byte[] cacheEntry;
+        try {
+            cacheEntry = toCacheEntry(parsed);
+        } catch (IOException ioe) {
+            Slog.e(TAG, "Unable to serialize parsed package for: " + packageFile);
+            return;
+        }
+
+        if (cacheEntry == null) {
+            return;
+        }
+
+        try (FileOutputStream fos = new FileOutputStream(cacheFile)) {
+            fos.write(cacheEntry);
+        } catch (IOException ioe) {
+            Slog.w(TAG, "Error writing cache entry.", ioe);
+            cacheFile.delete();
         }
     }
 
@@ -1696,6 +1856,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 +5610,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 +5648,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 +5714,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 +5730,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 +5768,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 +5817,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/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index cdf7013..aa109de 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -26,6 +26,7 @@
 import android.os.CancellationSignal.OnCancelListener;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.IRemoteCallback;
 import android.os.Looper;
 import android.os.PowerManager;
 import android.os.RemoteException;
@@ -757,20 +758,22 @@
                         new IFingerprintServiceLockoutResetCallback.Stub() {
 
                     @Override
-                    public void onLockoutReset(long deviceId) throws RemoteException {
-                        final PowerManager.WakeLock wakeLock = powerManager.newWakeLock(
-                                PowerManager.PARTIAL_WAKE_LOCK, "lockoutResetCallback");
-                        wakeLock.acquire();
-                        mHandler.post(new Runnable() {
-                            @Override
-                            public void run() {
+                    public void onLockoutReset(long deviceId, IRemoteCallback serverCallback)
+                            throws RemoteException {
+                        try {
+                            final PowerManager.WakeLock wakeLock = powerManager.newWakeLock(
+                                    PowerManager.PARTIAL_WAKE_LOCK, "lockoutResetCallback");
+                            wakeLock.acquire();
+                            mHandler.post(() -> {
                                 try {
                                     callback.onLockoutReset();
                                 } finally {
                                     wakeLock.release();
                                 }
-                            }
-                        });
+                            });
+                        } finally {
+                            serverCallback.sendResult(null /* data */);
+                        }
                     }
                 });
             } catch (RemoteException e) {
diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
index e027a2b3..971e14c 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
@@ -17,14 +17,17 @@
 
 import android.hardware.fingerprint.Fingerprint;
 import android.os.Bundle;
+import android.os.IRemoteCallback;
 import android.os.UserHandle;
 
 /**
  * Callback when lockout period expired and clients are allowed to authenticate again.
  * @hide
  */
-interface IFingerprintServiceLockoutResetCallback {
+oneway interface IFingerprintServiceLockoutResetCallback {
 
-    /** Method is synchronous so wakelock is held when this is called from a WAKEUP alarm. */
-    void onLockoutReset(long deviceId);
+    /**
+     * A wakelock will be held until the reciever calls back into {@param callback}
+     */
+    void onLockoutReset(long deviceId, IRemoteCallback callback);
 }
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..0b78d6b 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1321,6 +1321,20 @@
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_WEBVIEW_SETTINGS = "android.settings.WEBVIEW_SETTINGS";
 
+    /**
+     * Activity Action: Show enterprise privacy section.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS
+            = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
+
     // End of Intent actions for Settings
 
     /**
@@ -7741,6 +7755,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/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index bccb822..bd1ad8e 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -20,6 +20,7 @@
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
 
 import android.content.res.CompatibilityInfo;
@@ -210,8 +211,7 @@
     boolean isKeyguardLocked();
     boolean isKeyguardSecure();
     boolean inKeyguardRestrictedInputMode();
-    void dismissKeyguard();
-    void keyguardGoingAway(int flags);
+    void dismissKeyguard(IKeyguardDismissCallback callback);
 
     // Requires INTERACT_ACROSS_USERS_FULL permission
     void setSwitchingUser(boolean switching);
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index c46acae..0da710a 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -28,6 +28,8 @@
 import android.widget.ImageView;
 import android.widget.RemoteViews;
 
+import com.android.internal.widget.CachingIconView;
+
 import java.util.ArrayList;
 
 /**
@@ -45,7 +47,7 @@
     private OnClickListener mExpandClickListener;
     private HeaderTouchListener mTouchListener = new HeaderTouchListener();
     private ImageView mExpandButton;
-    private View mIcon;
+    private CachingIconView mIcon;
     private View mProfileBadge;
     private View mInfo;
     private int mIconColor;
@@ -123,7 +125,7 @@
         if (mExpandButton != null) {
             mExpandButton.setAccessibilityDelegate(mExpandDelegate);
         }
-        mIcon = findViewById(com.android.internal.R.id.icon);
+        mIcon = (CachingIconView) findViewById(com.android.internal.R.id.icon);
         mProfileBadge = findViewById(com.android.internal.R.id.profile_badge);
     }
 
@@ -311,6 +313,10 @@
         return mProfileBadge;
     }
 
+    public CachingIconView getIcon() {
+        return mIcon;
+    }
+
     public class HeaderTouchListener implements View.OnTouchListener {
 
         private final ArrayList<Rect> mTouchRects = new ArrayList<>();
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..7c1bcee 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 =
@@ -579,8 +580,10 @@
          * Called when a window is dismissed. This informs the callback that the
          * window is gone, and it should finish itself.
          * @param finishTask True if the task should also be finished.
+         * @param suppressWindowTransition True if the resulting exit and enter window transition
+         * animations should be suppressed.
          */
-        void onWindowDismissed(boolean finishTask);
+        void onWindowDismissed(boolean finishTask, boolean suppressWindowTransition);
     }
 
     /** @hide */
@@ -869,9 +872,10 @@
     }
 
     /** @hide */
-    public final void dispatchOnWindowDismissed(boolean finishTask) {
+    public final void dispatchOnWindowDismissed(
+            boolean finishTask, boolean suppressWindowTransition) {
         if (mOnWindowDismissedCallback != null) {
-            mOnWindowDismissedCallback.onWindowDismissed(finishTask);
+            mOnWindowDismissedCallback.onWindowDismissed(finishTask, suppressWindowTransition);
         }
     }
 
@@ -2209,4 +2213,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 2971280..aa7631d 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.app.KeyguardManager;
 import android.app.Presentation;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
@@ -911,17 +912,21 @@
         public static final int FLAG_TURN_SCREEN_ON = 0x00200000;
 
         /** Window flag: when set the window will cause the keyguard to
-         * be dismissed, only if it is not a secure lock keyguard.  Because such
+         * be dismissed, only if it is not a secure lock keyguard. Because such
          * a keyguard is not needed for security, it will never re-appear if
          * the user navigates to another window (in contrast to
          * {@link #FLAG_SHOW_WHEN_LOCKED}, which will only temporarily
          * hide both secure and non-secure keyguards but ensure they reappear
          * when the user moves to another UI that doesn't hide them).
          * If the keyguard is currently active and is secure (requires an
-         * unlock pattern) than the user will still need to confirm it before
+         * 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.
+         * @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 82379c4..2f55fc9 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.app.ActivityManager.StackId;
 import android.content.Context;
@@ -31,6 +32,7 @@
 import android.os.RemoteException;
 import android.view.animation.Animation;
 
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
 
 import java.io.PrintWriter;
@@ -480,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);
@@ -1162,8 +1174,10 @@
 
     /**
      * Ask the policy to dismiss the keyguard, if it is currently shown.
+     *
+     * @param callback Callback to be informed about the result.
      */
-    public void dismissKeyguardLw();
+    public void dismissKeyguardLw(@Nullable IKeyguardDismissCallback callback);
 
     /**
      * Ask the policy whether the Keyguard has drawn. If the Keyguard is disabled, this method
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/android/widget/EditText.java b/core/java/android/widget/EditText.java
index a8d3984..043eb34 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -142,6 +142,12 @@
 
     /** @hide */
     @Override
+    protected boolean supportsAutoSizeText() {
+        return false;
+    }
+
+    /** @hide */
+    @Override
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
         if (isEnabled()) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index b85175d..44655f1 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1534,7 +1534,7 @@
         }
 
         // Setup auto-size.
-        if (mEditor == null) {
+        if (supportsAutoSizeText()) {
             switch (mAutoSizeType) {
                 case AUTO_SIZE_TYPE_NONE:
                     // Nothing to do.
@@ -9261,8 +9261,8 @@
     }
 
     /**
-     * @return true if this TextView is specialized for showing and interacting with the extracted
-     * text in a full-screen input method.
+     * @return {@code true} if this TextView is specialized for showing and interacting with the
+     * extracted text in a full-screen input method.
      * @hide
      */
     public boolean isInExtractedMode() {
@@ -9270,6 +9270,14 @@
     }
 
     /**
+     * @return {@code true} if this TextView supports autosizing text to fit within its container.
+     * @hide
+     */
+    protected boolean supportsAutoSizeText() {
+        return true;
+    }
+
+    /**
      * This is a temporary method. Future versions may support multi-locale text.
      * Caveat: This method may not return the latest spell checker locale, but this should be
      * acceptable and it's more important to make this method asynchronous.
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/IKeyguardDismissCallback.aidl b/core/java/com/android/internal/policy/IKeyguardDismissCallback.aidl
new file mode 100644
index 0000000..635c504
--- /dev/null
+++ b/core/java/com/android/internal/policy/IKeyguardDismissCallback.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.policy;
+
+oneway interface IKeyguardDismissCallback {
+    void onDismissError();
+    void onDismissSucceeded();
+    void onDismissCancelled();
+}
diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl
index 788103d..a019ea1 100644
--- a/core/java/com/android/internal/policy/IKeyguardService.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardService.aidl
@@ -16,6 +16,7 @@
 package com.android.internal.policy;
 
 import com.android.internal.policy.IKeyguardDrawnCallback;
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IKeyguardStateCallback;
 import com.android.internal.policy.IKeyguardExitCallback;
 
@@ -34,7 +35,7 @@
 
     void addStateMonitorCallback(IKeyguardStateCallback callback);
     void verifyUnlock(IKeyguardExitCallback callback);
-    void dismiss(boolean allowWhileOccluded);
+    void dismiss(IKeyguardDismissCallback callback);
     void onDreamingStarted();
     void onDreamingStopped();
 
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 2a004cfb..ec068a3 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,25 +2988,26 @@
         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) {
-                dispatchOnWindowDismissed(false /*finishTask*/);
+                dispatchOnWindowDismissed(false /*finishTask*/, true /*suppressWindowTransition*/);
             }
         });
         swipeDismiss.setOnSwipeProgressChangedListener(
                 new SwipeDismissLayout.OnSwipeProgressChangedListener() {
-                    private static final float ALPHA_DECREASE = 0.5f;
-                    private boolean mIsTranslucent = false;
                     @Override
                     public void onSwipeProgressChanged(
-                            SwipeDismissLayout layout, float progress, float translate) {
+                            SwipeDismissLayout layout, float alpha, float translate) {
                         WindowManager.LayoutParams newParams = getAttributes();
                         newParams.x = (int) translate;
-                        newParams.alpha = 1 - (progress * ALPHA_DECREASE);
+                        newParams.alpha = alpha;
                         setAttributes(newParams);
 
                         int flags = 0;
@@ -3028,6 +3030,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/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index b0d45e1d1..be10608df 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -1190,6 +1190,26 @@
         }
 
         /**
+         * Remove a state from the state machine. Will not remove the state if it is currently
+         * active or if it has any children in the hierarchy.
+         * @param state the state to remove
+         */
+        private void removeState(State state) {
+            StateInfo stateInfo = mStateInfo.get(state);
+            if (stateInfo == null || stateInfo.active) {
+                return;
+            }
+            boolean isParent = mStateInfo.values().stream()
+                    .filter(si -> si.parentStateInfo == stateInfo)
+                    .findAny()
+                    .isPresent();
+            if (isParent) {
+                return;
+            }
+            mStateInfo.remove(state);
+        }
+
+        /**
          * Constructor
          *
          * @param looper for dispatching messages
@@ -1337,6 +1357,14 @@
     }
 
     /**
+     * Removes a state from the state machine, unless it is currently active or if it has children.
+     * @param state state to remove
+     */
+    public final void removeState(State state) {
+        mSmHandler.removeState(state);
+    }
+
+    /**
      * Set the initial state. This must be invoked before
      * and messages are sent to the state machine.
      *
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/CachingIconView.java b/core/java/com/android/internal/widget/CachingIconView.java
index 293b77b..20230cd 100644
--- a/core/java/com/android/internal/widget/CachingIconView.java
+++ b/core/java/com/android/internal/widget/CachingIconView.java
@@ -41,6 +41,8 @@
     private String mLastPackage;
     private int mLastResId;
     private boolean mInternalSetDrawable;
+    private boolean mForceHidden;
+    private int mDesiredVisibility;
 
     public CachingIconView(Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
@@ -175,4 +177,24 @@
         mLastResId = 0;
         mLastPackage = null;
     }
+
+    /**
+     * Set the icon to be forcibly hidden, even when it's visibility is changed to visible.
+     */
+    public void setForceHidden(boolean forceHidden) {
+        mForceHidden = forceHidden;
+        updateVisibility();
+    }
+
+    @Override
+    public void setVisibility(int visibility) {
+        mDesiredVisibility = visibility;
+        updateVisibility();
+    }
+
+    private void updateVisibility() {
+        int visibility = mDesiredVisibility == VISIBLE && mForceHidden ? INVISIBLE
+                : mDesiredVisibility;
+        super.setVisibility(visibility);
+    }
 }
diff --git a/core/java/com/android/internal/widget/DecorCaptionView.java b/core/java/com/android/internal/widget/DecorCaptionView.java
index c458ab1..b419113 100644
--- a/core/java/com/android/internal/widget/DecorCaptionView.java
+++ b/core/java/com/android/internal/widget/DecorCaptionView.java
@@ -408,7 +408,8 @@
         if (mClickTarget == mMaximize) {
             maximizeWindow();
         } else if (mClickTarget == mClose) {
-            mOwner.dispatchOnWindowDismissed(true /*finishTask*/);
+            mOwner.dispatchOnWindowDismissed(
+                    true /*finishTask*/, false /*suppressWindowTransition*/);
         }
         return true;
     }
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index b0bc81b..63b700b 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1432,7 +1432,8 @@
                         STRONG_AUTH_REQUIRED_AFTER_BOOT,
                         STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
                         SOME_AUTH_REQUIRED_AFTER_USER_REQUEST,
-                        STRONG_AUTH_REQUIRED_AFTER_LOCKOUT})
+                        STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
+                        STRONG_AUTH_REQUIRED_AFTER_TIMEOUT})
         @Retention(RetentionPolicy.SOURCE)
         public @interface StrongAuthFlags {}
 
@@ -1463,6 +1464,12 @@
         public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8;
 
         /**
+         * Strong authentication is required because it hasn't been used for a time required by
+         * a device admin.
+         */
+        public static final int STRONG_AUTH_REQUIRED_AFTER_TIMEOUT = 0x10;
+
+        /**
          * Strong auth flags that do not prevent fingerprint from being accepted as auth.
          *
          * If any other flags are set, fingerprint is disabled.
diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java
index d88f479..83b49eb 100644
--- a/core/java/com/android/internal/widget/SwipeDismissLayout.java
+++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java
@@ -16,6 +16,10 @@
 
 package com.android.internal.widget;
 
+import android.animation.Animator;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.app.Activity;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -30,6 +34,7 @@
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
+import android.view.animation.DecelerateInterpolator;
 import android.widget.FrameLayout;
 
 /**
@@ -49,12 +54,12 @@
         /**
          * Called when the layout has been swiped and the position of the window should change.
          *
-         * @param progress A number in [0, 1] representing how far to the
-         * right the window has been swiped
+         * @param alpha A number in [0, 1] representing what the alpha transparency of the window
+         * should be.
          * @param translate A number in [0, w], where w is the width of the
          * layout. This is equivalent to progress * layout.getWidth().
          */
-        void onSwipeProgressChanged(SwipeDismissLayout layout, float progress, float translate);
+        void onSwipeProgressChanged(SwipeDismissLayout layout, float alpha, float translate);
 
         void onSwipeCancelled(SwipeDismissLayout layout);
     }
@@ -72,6 +77,9 @@
     private boolean mDiscardIntercept;
     private VelocityTracker mVelocityTracker;
     private float mTranslationX;
+    private boolean mBlockGesture = false;
+
+    private final DismissAnimator mDismissAnimator = new DismissAnimator();
 
     private OnDismissedListener mDismissedListener;
     private OnSwipeProgressChangedListener mProgressListener;
@@ -110,6 +118,8 @@
 
     private float mLastX;
 
+    private boolean mDismissable = true;
+
     public SwipeDismissLayout(Context context) {
         super(context);
         init(context);
@@ -166,6 +176,14 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
+        checkGesture((ev));
+        if (mBlockGesture) {
+            return true;
+        }
+        if (!mDismissable) {
+            return super.onInterceptTouchEvent(ev);
+        }
+
         // offset because the view is translated during swipe
         ev.offsetLocation(mTranslationX, 0);
 
@@ -225,7 +243,11 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
-        if (mVelocityTracker == null) {
+        checkGesture((ev));
+        if (mBlockGesture) {
+            return true;
+        }
+        if (mVelocityTracker == null || !mDismissable) {
             return super.onTouchEvent(ev);
         }
         // offset because the view is translated during swipe
@@ -234,9 +256,9 @@
             case MotionEvent.ACTION_UP:
                 updateDismiss(ev);
                 if (mDismissed) {
-                    dismiss();
+                    mDismissAnimator.animateDismissal(ev.getRawX() - mDownX);
                 } else if (mSwiping) {
-                    cancel();
+                    mDismissAnimator.animateRecovery(ev.getRawX() - mDownX);
                 }
                 resetMembers();
                 break;
@@ -264,7 +286,8 @@
     private void setProgress(float deltaX) {
         mTranslationX = deltaX;
         if (mProgressListener != null && deltaX >= 0)  {
-            mProgressListener.onSwipeProgressChanged(this, deltaX / getWidth(), deltaX);
+            mProgressListener.onSwipeProgressChanged(
+                    this, progressToAlpha(deltaX / getWidth()), deltaX);
         }
     }
 
@@ -363,4 +386,100 @@
 
         return checkV && v.canScrollHorizontally((int) -dx);
     }
+
+    public void setDismissable(boolean dismissable) {
+        if (!dismissable && mDismissable) {
+            cancel();
+            resetMembers();
+        }
+
+        mDismissable = dismissable;
+    }
+
+    private void checkGesture(MotionEvent ev) {
+        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
+            mBlockGesture = mDismissAnimator.isAnimating();
+        }
+    }
+
+    private float progressToAlpha(float progress) {
+        return 1 - progress * progress * progress;
+    }
+
+    private class DismissAnimator implements AnimatorUpdateListener, Animator.AnimatorListener {
+        private final TimeInterpolator DISMISS_INTERPOLATOR = new DecelerateInterpolator(1.5f);
+        private final long DISMISS_DURATION = 250;
+
+        private final ValueAnimator mDismissAnimator = new ValueAnimator();
+        private boolean mWasCanceled = false;
+        private boolean mDismissOnComplete = false;
+
+        /* package */ DismissAnimator() {
+            mDismissAnimator.addUpdateListener(this);
+            mDismissAnimator.addListener(this);
+        }
+
+        /* package */ void animateDismissal(float currentTranslation) {
+            animate(
+                    currentTranslation / getWidth(),
+                    1,
+                    DISMISS_DURATION,
+                    DISMISS_INTERPOLATOR,
+                    true /* dismiss */);
+        }
+
+        /* package */ void animateRecovery(float currentTranslation) {
+            animate(
+                    currentTranslation / getWidth(),
+                    0,
+                    DISMISS_DURATION,
+                    DISMISS_INTERPOLATOR,
+                    false /* don't dismiss */);
+        }
+
+        /* package */ boolean isAnimating() {
+            return mDismissAnimator.isStarted();
+        }
+
+        private void animate(float from, float to, long duration, TimeInterpolator interpolator,
+                boolean dismissOnComplete) {
+            mDismissAnimator.cancel();
+            mDismissOnComplete = dismissOnComplete;
+            mDismissAnimator.setFloatValues(from, to);
+            mDismissAnimator.setDuration(duration);
+            mDismissAnimator.setInterpolator(interpolator);
+            mDismissAnimator.start();
+        }
+
+        @Override
+        public void onAnimationUpdate(ValueAnimator animation) {
+            float value = (Float) animation.getAnimatedValue();
+            setProgress(value * getWidth());
+        }
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+            mWasCanceled = false;
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            mWasCanceled = true;
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            if (!mWasCanceled) {
+                if (mDismissOnComplete) {
+                    dismiss();
+                } else {
+                    cancel();
+                }
+            }
+        }
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+        }
+    }
 }
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index a4e9576..e447dd2 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 \
@@ -250,22 +249,18 @@
     libGLESv1_CM \
     libGLESv2 \
     libvulkan \
+    libziparchive \
     libETC1 \
     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_GLES10.cpp b/core/jni/android_opengl_GLES10.cpp
index f4135c2..64c9fe8 100644
--- a/core/jni/android_opengl_GLES10.cpp
+++ b/core/jni/android_opengl_GLES10.cpp
@@ -600,6 +600,9 @@
 static void
 android_glColorPointerBounds__IIILjava_nio_Buffer_2I
   (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jobject pointer_buf, jint remaining) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
@@ -618,17 +621,29 @@
         (GLvoid *)pointer,
         (GLsizei)remaining
     );
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glCompressedTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data ) */
 static void
 android_glCompressedTexImage2D__IIIIIIILjava_nio_Buffer_2
   (JNIEnv *_env, jobject _this, jint target, jint level, jint internalformat, jint width, jint height, jint border, jint imageSize, jobject data_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLvoid *data = (GLvoid *) 0;
 
+    if (!data_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "data == null";
+        goto exit;
+    }
     data = (GLvoid *)getPointer(_env, data_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (data == NULL) {
         char * _dataBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
@@ -644,20 +659,34 @@
         (GLsizei)imageSize,
         (GLvoid *)data
     );
+
+exit:
     if (_array) {
         releasePointer(_env, _array, data, JNI_FALSE);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glCompressedTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data ) */
 static void
 android_glCompressedTexSubImage2D__IIIIIIIILjava_nio_Buffer_2
   (JNIEnv *_env, jobject _this, jint target, jint level, jint xoffset, jint yoffset, jint width, jint height, jint format, jint imageSize, jobject data_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLvoid *data = (GLvoid *) 0;
 
+    if (!data_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "data == null";
+        goto exit;
+    }
     data = (GLvoid *)getPointer(_env, data_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (data == NULL) {
         char * _dataBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
@@ -674,9 +703,14 @@
         (GLsizei)imageSize,
         (GLvoid *)data
     );
+
+exit:
     if (_array) {
         releasePointer(_env, _array, data, JNI_FALSE);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glCopyTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border ) */
@@ -781,6 +815,12 @@
     jint _remaining;
     GLuint *textures = (GLuint *) 0;
 
+    if (!textures_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "textures == null";
+        goto exit;
+    }
     textures = (GLuint *)getPointer(_env, textures_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -885,6 +925,12 @@
     jint _remaining;
     GLvoid *indices = (GLvoid *) 0;
 
+    if (!indices_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "indices == null";
+        goto exit;
+    }
     indices = (GLvoid *)getPointer(_env, indices_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < count) {
         _exception = 1;
@@ -1026,6 +1072,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -1144,6 +1196,12 @@
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -1278,6 +1336,12 @@
     jint _remaining;
     GLuint *textures = (GLuint *) 0;
 
+    if (!textures_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "textures == null";
+        goto exit;
+    }
     textures = (GLuint *)getPointer(_env, textures_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -1424,6 +1488,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -1542,6 +1612,12 @@
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -1676,6 +1752,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -1825,6 +1907,12 @@
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -1947,11 +2035,20 @@
 static void
 android_glLoadMatrixf__Ljava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jobject m_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *m = (GLfloat *) 0;
 
+    if (!m_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "m == null";
+        goto exit;
+    }
     m = (GLfloat *)getPointer(_env, m_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (m == NULL) {
         char * _mBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -1960,9 +2057,14 @@
     glLoadMatrixf(
         (GLfloat *)m
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)m, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glLoadMatrixx ( const GLfixed *m ) */
@@ -2011,11 +2113,20 @@
 static void
 android_glLoadMatrixx__Ljava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jobject m_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *m = (GLfixed *) 0;
 
+    if (!m_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "m == null";
+        goto exit;
+    }
     m = (GLfixed *)getPointer(_env, m_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (m == NULL) {
         char * _mBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -2024,9 +2135,14 @@
     glLoadMatrixx(
         (GLfixed *)m
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)m, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glLogicOp ( GLenum opcode ) */
@@ -2134,6 +2250,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -2279,6 +2401,12 @@
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -2383,11 +2511,20 @@
 static void
 android_glMultMatrixf__Ljava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jobject m_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *m = (GLfloat *) 0;
 
+    if (!m_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "m == null";
+        goto exit;
+    }
     m = (GLfloat *)getPointer(_env, m_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (m == NULL) {
         char * _mBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -2396,9 +2533,14 @@
     glMultMatrixf(
         (GLfloat *)m
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)m, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glMultMatrixx ( const GLfixed *m ) */
@@ -2447,11 +2589,20 @@
 static void
 android_glMultMatrixx__Ljava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jobject m_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *m = (GLfixed *) 0;
 
+    if (!m_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "m == null";
+        goto exit;
+    }
     m = (GLfixed *)getPointer(_env, m_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (m == NULL) {
         char * _mBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -2460,9 +2611,14 @@
     glMultMatrixx(
         (GLfixed *)m
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)m, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glMultiTexCoord4f ( GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q ) */
@@ -2517,6 +2673,9 @@
 static void
 android_glNormalPointerBounds__IILjava_nio_Buffer_2I
   (JNIEnv *_env, jobject _this, jint type, jint stride, jobject pointer_buf, jint remaining) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
@@ -2534,6 +2693,9 @@
         (GLvoid *)pointer,
         (GLsizei)remaining
     );
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glOrthof ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) */
@@ -2630,11 +2792,20 @@
 static void
 android_glReadPixels__IIIIIILjava_nio_Buffer_2
   (JNIEnv *_env, jobject _this, jint x, jint y, jint width, jint height, jint format, jint type, jobject pixels_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLvoid *pixels = (GLvoid *) 0;
 
+    if (!pixels_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "pixels == null";
+        goto exit;
+    }
     pixels = (GLvoid *)getPointer(_env, pixels_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (pixels == NULL) {
         char * _pixelsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
@@ -2649,8 +2820,13 @@
         (GLenum)type,
         (GLvoid *)pixels
     );
+
+exit:
     if (_array) {
-        releasePointer(_env, _array, pixels, JNI_TRUE);
+        releasePointer(_env, _array, pixels, _exception ? JNI_FALSE : JNI_TRUE);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -2776,6 +2952,9 @@
 static void
 android_glTexCoordPointerBounds__IIILjava_nio_Buffer_2I
   (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jobject pointer_buf, jint remaining) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
@@ -2794,6 +2973,9 @@
         (GLvoid *)pointer,
         (GLsizei)remaining
     );
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glTexEnvf ( GLenum target, GLenum pname, GLfloat param ) */
@@ -2880,6 +3062,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -3001,6 +3189,12 @@
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -3042,6 +3236,9 @@
 static void
 android_glTexImage2D__IIIIIIIILjava_nio_Buffer_2
   (JNIEnv *_env, jobject _this, jint target, jint level, jint internalformat, jint width, jint height, jint border, jint format, jint type, jobject pixels_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
@@ -3068,6 +3265,9 @@
     if (_array) {
         releasePointer(_env, _array, pixels, JNI_FALSE);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glTexParameterf ( GLenum target, GLenum pname, GLfloat param ) */
@@ -3096,6 +3296,9 @@
 static void
 android_glTexSubImage2D__IIIIIIIILjava_nio_Buffer_2
   (JNIEnv *_env, jobject _this, jint target, jint level, jint xoffset, jint yoffset, jint width, jint height, jint format, jint type, jobject pixels_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
@@ -3122,6 +3325,9 @@
     if (_array) {
         releasePointer(_env, _array, pixels, JNI_FALSE);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glTranslatef ( GLfloat x, GLfloat y, GLfloat z ) */
@@ -3150,6 +3356,9 @@
 static void
 android_glVertexPointerBounds__IIILjava_nio_Buffer_2I
   (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jobject pointer_buf, jint remaining) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
@@ -3168,6 +3377,9 @@
         (GLvoid *)pointer,
         (GLsizei)remaining
     );
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glViewport ( GLint x, GLint y, GLsizei width, GLsizei height ) */
diff --git a/core/jni/android_opengl_GLES10Ext.cpp b/core/jni/android_opengl_GLES10Ext.cpp
index 4dc4233..533bda4 100644
--- a/core/jni/android_opengl_GLES10Ext.cpp
+++ b/core/jni/android_opengl_GLES10Ext.cpp
@@ -540,6 +540,12 @@
     jint _exponentRemaining;
     GLint *exponent = (GLint *) 0;
 
+    if (!mantissa_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "mantissa == null";
+        goto exit;
+    }
     mantissa = (GLfixed *)getPointer(_env, mantissa_buf, (jarray*)&_mantissaArray, &_mantissaRemaining, &_mantissaBufferOffset);
     if (_mantissaRemaining < 16) {
         _exception = 1;
@@ -547,6 +553,12 @@
         _exceptionMessage = "remaining() < 16 < needed";
         goto exit;
     }
+    if (!exponent_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "exponent == null";
+        goto exit;
+    }
     exponent = (GLint *)getPointer(_env, exponent_buf, (jarray*)&_exponentArray, &_exponentRemaining, &_exponentBufferOffset);
     if (_exponentRemaining < 16) {
         _exception = 1;
diff --git a/core/jni/android_opengl_GLES11.cpp b/core/jni/android_opengl_GLES11.cpp
index 2625e03..923f7a8 100644
--- a/core/jni/android_opengl_GLES11.cpp
+++ b/core/jni/android_opengl_GLES11.cpp
@@ -505,6 +505,12 @@
     jint _remaining;
     GLvoid *data = (GLvoid *) 0;
 
+    if (!data_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "data == null";
+        goto exit;
+    }
     data = (GLvoid *)getPointer(_env, data_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < size) {
         _exception = 1;
@@ -587,6 +593,12 @@
     jint _remaining;
     GLfloat *equation = (GLfloat *) 0;
 
+    if (!equation_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "equation == null";
+        goto exit;
+    }
     equation = (GLfloat *)getPointer(_env, equation_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (equation == NULL) {
         char * _equationBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -596,6 +608,8 @@
         (GLenum)plane,
         (GLfloat *)equation
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)equation, JNI_ABORT);
     }
@@ -659,6 +673,12 @@
     jint _remaining;
     GLfixed *equation = (GLfixed *) 0;
 
+    if (!equation_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "equation == null";
+        goto exit;
+    }
     equation = (GLfixed *)getPointer(_env, equation_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (equation == NULL) {
         char * _equationBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -668,6 +688,8 @@
         (GLenum)plane,
         (GLfixed *)equation
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)equation, JNI_ABORT);
     }
@@ -761,6 +783,12 @@
     jint _remaining;
     GLuint *buffers = (GLuint *) 0;
 
+    if (!buffers_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "buffers == null";
+        goto exit;
+    }
     buffers = (GLuint *)getPointer(_env, buffers_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -865,6 +893,12 @@
     jint _remaining;
     GLuint *buffers = (GLuint *) 0;
 
+    if (!buffers_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "buffers == null";
+        goto exit;
+    }
     buffers = (GLuint *)getPointer(_env, buffers_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -967,6 +1001,12 @@
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -1054,6 +1094,12 @@
     jint _remaining;
     GLfloat *eqn = (GLfloat *) 0;
 
+    if (!eqn_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "eqn == null";
+        goto exit;
+    }
     eqn = (GLfloat *)getPointer(_env, eqn_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 4) {
         _exception = 1;
@@ -1140,6 +1186,12 @@
     jint _remaining;
     GLfixed *eqn = (GLfixed *) 0;
 
+    if (!eqn_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "eqn == null";
+        goto exit;
+    }
     eqn = (GLfixed *)getPointer(_env, eqn_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 4) {
         _exception = 1;
@@ -1212,11 +1264,20 @@
 static void
 android_glGetFixedv__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1226,8 +1287,13 @@
         (GLenum)pname,
         (GLfixed *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -1333,6 +1399,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -1471,6 +1543,12 @@
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -1607,6 +1685,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -1741,6 +1825,12 @@
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -1863,6 +1953,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -1973,6 +2069,12 @@
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -2083,6 +2185,12 @@
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -2182,6 +2290,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -2270,6 +2384,12 @@
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -2358,6 +2478,12 @@
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -2499,6 +2625,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -2595,6 +2727,12 @@
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -2624,6 +2762,9 @@
 static void
 android_glPointSizePointerOESBounds__IILjava_nio_Buffer_2I
   (JNIEnv *_env, jobject _this, jint type, jint stride, jobject pointer_buf, jint remaining) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
@@ -2641,6 +2782,9 @@
         (GLvoid *)pointer,
         (GLsizei)remaining
     );
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glTexCoordPointer ( GLint size, GLenum type, GLsizei stride, GLint offset ) */
@@ -2739,6 +2883,12 @@
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -2838,6 +2988,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -2937,6 +3093,12 @@
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -3025,6 +3187,12 @@
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
diff --git a/core/jni/android_opengl_GLES11Ext.cpp b/core/jni/android_opengl_GLES11Ext.cpp
index fb85cb0..f7498d5 100644
--- a/core/jni/android_opengl_GLES11Ext.cpp
+++ b/core/jni/android_opengl_GLES11Ext.cpp
@@ -572,6 +572,12 @@
     jint _remaining;
     GLshort *coords = (GLshort *) 0;
 
+    if (!coords_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "coords == null";
+        goto exit;
+    }
     coords = (GLshort *)getPointer(_env, coords_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 5) {
         _exception = 1;
@@ -656,6 +662,12 @@
     jint _remaining;
     GLint *coords = (GLint *) 0;
 
+    if (!coords_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "coords == null";
+        goto exit;
+    }
     coords = (GLint *)getPointer(_env, coords_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 5) {
         _exception = 1;
@@ -740,6 +752,12 @@
     jint _remaining;
     GLfixed *coords = (GLfixed *) 0;
 
+    if (!coords_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "coords == null";
+        goto exit;
+    }
     coords = (GLfixed *)getPointer(_env, coords_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 5) {
         _exception = 1;
@@ -837,6 +855,12 @@
     jint _remaining;
     GLfloat *coords = (GLfloat *) 0;
 
+    if (!coords_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "coords == null";
+        goto exit;
+    }
     coords = (GLfloat *)getPointer(_env, coords_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 5) {
         _exception = 1;
@@ -865,11 +889,20 @@
 static void
 android_glEGLImageTargetTexture2DOES__ILjava_nio_Buffer_2
   (JNIEnv *_env, jobject _this, jint target, jobject image_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLeglImageOES image = (GLeglImageOES) 0;
 
+    if (!image_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "image == null";
+        goto exit;
+    }
     image = (GLeglImageOES)getPointer(_env, image_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (image == NULL) {
         char * _imageBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
@@ -879,8 +912,13 @@
         (GLenum)target,
         (GLeglImageOES)image
     );
+
+exit:
     if (_array) {
-        releasePointer(_env, _array, image, JNI_TRUE);
+        releasePointer(_env, _array, image, _exception ? JNI_FALSE : JNI_TRUE);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -888,11 +926,20 @@
 static void
 android_glEGLImageTargetRenderbufferStorageOES__ILjava_nio_Buffer_2
   (JNIEnv *_env, jobject _this, jint target, jobject image_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLeglImageOES image = (GLeglImageOES) 0;
 
+    if (!image_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "image == null";
+        goto exit;
+    }
     image = (GLeglImageOES)getPointer(_env, image_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (image == NULL) {
         char * _imageBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
@@ -902,8 +949,13 @@
         (GLenum)target,
         (GLeglImageOES)image
     );
+
+exit:
     if (_array) {
-        releasePointer(_env, _array, image, JNI_TRUE);
+        releasePointer(_env, _array, image, _exception ? JNI_FALSE : JNI_TRUE);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -985,11 +1037,20 @@
 static void
 android_glClipPlanexOES__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint plane, jobject equation_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *equation = (GLfixed *) 0;
 
+    if (!equation_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "equation == null";
+        goto exit;
+    }
     equation = (GLfixed *)getPointer(_env, equation_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (equation == NULL) {
         char * _equationBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -999,9 +1060,14 @@
         (GLenum)plane,
         (GLfixed *)equation
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)equation, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glColor4xOES ( GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha ) */
@@ -1083,11 +1149,20 @@
 static void
 android_glFogxvOES__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1097,9 +1172,14 @@
         (GLenum)pname,
         (GLfixed *)params
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)params, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glFrustumxOES ( GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar ) */
@@ -1177,6 +1257,12 @@
     jint _remaining;
     GLfixed *eqn = (GLfixed *) 0;
 
+    if (!eqn_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "eqn == null";
+        goto exit;
+    }
     eqn = (GLfixed *)getPointer(_env, eqn_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 4) {
         _exception = 1;
@@ -1249,11 +1335,20 @@
 static void
 android_glGetFixedvOES__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1263,8 +1358,13 @@
         (GLenum)pname,
         (GLfixed *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -1316,11 +1416,20 @@
 static void
 android_glGetLightxvOES__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint light, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1331,8 +1440,13 @@
         (GLenum)pname,
         (GLfixed *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -1384,11 +1498,20 @@
 static void
 android_glGetMaterialxvOES__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint face, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1399,8 +1522,13 @@
         (GLenum)pname,
         (GLfixed *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -1452,11 +1580,20 @@
 static void
 android_glGetTexEnvxvOES__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint env, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1467,8 +1604,13 @@
         (GLenum)pname,
         (GLfixed *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -1520,11 +1662,20 @@
 static void
 android_glGetTexParameterxvOES__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1535,8 +1686,13 @@
         (GLenum)pname,
         (GLfixed *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -1597,11 +1753,20 @@
 static void
 android_glLightModelxvOES__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1611,9 +1776,14 @@
         (GLenum)pname,
         (GLfixed *)params
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)params, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glLightxOES ( GLenum light, GLenum pname, GLfixed param ) */
@@ -1675,11 +1845,20 @@
 static void
 android_glLightxvOES__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint light, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1690,9 +1869,14 @@
         (GLenum)pname,
         (GLfixed *)params
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)params, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glLineWidthxOES ( GLfixed width ) */
@@ -1750,11 +1934,20 @@
 static void
 android_glLoadMatrixxOES__Ljava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jobject m_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *m = (GLfixed *) 0;
 
+    if (!m_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "m == null";
+        goto exit;
+    }
     m = (GLfixed *)getPointer(_env, m_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (m == NULL) {
         char * _mBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1763,9 +1956,14 @@
     glLoadMatrixxOES(
         (GLfixed *)m
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)m, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glMaterialxOES ( GLenum face, GLenum pname, GLfixed param ) */
@@ -1827,11 +2025,20 @@
 static void
 android_glMaterialxvOES__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint face, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1842,9 +2049,14 @@
         (GLenum)pname,
         (GLfixed *)params
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)params, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glMultMatrixxOES ( const GLfixed *m ) */
@@ -1893,11 +2105,20 @@
 static void
 android_glMultMatrixxOES__Ljava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jobject m_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *m = (GLfixed *) 0;
 
+    if (!m_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "m == null";
+        goto exit;
+    }
     m = (GLfixed *)getPointer(_env, m_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (m == NULL) {
         char * _mBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1906,9 +2127,14 @@
     glMultMatrixxOES(
         (GLfixed *)m
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)m, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glMultiTexCoord4xOES ( GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q ) */
@@ -2006,11 +2232,20 @@
 static void
 android_glPointParameterxvOES__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -2020,9 +2255,14 @@
         (GLenum)pname,
         (GLfixed *)params
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)params, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glPointSizexOES ( GLfixed size ) */
@@ -2136,11 +2376,20 @@
 static void
 android_glTexEnvxvOES__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -2151,9 +2400,14 @@
         (GLenum)pname,
         (GLfixed *)params
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)params, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glTexParameterxOES ( GLenum target, GLenum pname, GLfixed param ) */
@@ -2215,11 +2469,20 @@
 static void
 android_glTexParameterxvOES__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -2230,9 +2493,14 @@
         (GLenum)pname,
         (GLfixed *)params
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)params, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glTranslatexOES ( GLfixed x, GLfixed y, GLfixed z ) */
@@ -2328,6 +2596,12 @@
     jint _remaining;
     GLuint *renderbuffers = (GLuint *) 0;
 
+    if (!renderbuffers_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "renderbuffers == null";
+        goto exit;
+    }
     renderbuffers = (GLuint *)getPointer(_env, renderbuffers_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -2414,6 +2688,12 @@
     jint _remaining;
     GLuint *renderbuffers = (GLuint *) 0;
 
+    if (!renderbuffers_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "renderbuffers == null";
+        goto exit;
+    }
     renderbuffers = (GLuint *)getPointer(_env, renderbuffers_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -2513,6 +2793,12 @@
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -2621,6 +2907,12 @@
     jint _remaining;
     GLuint *framebuffers = (GLuint *) 0;
 
+    if (!framebuffers_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "framebuffers == null";
+        goto exit;
+    }
     framebuffers = (GLuint *)getPointer(_env, framebuffers_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -2707,6 +2999,12 @@
     jint _remaining;
     GLuint *framebuffers = (GLuint *) 0;
 
+    if (!framebuffers_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "framebuffers == null";
+        goto exit;
+    }
     framebuffers = (GLuint *)getPointer(_env, framebuffers_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -2831,6 +3129,12 @@
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -2887,6 +3191,9 @@
 static void
 android_glMatrixIndexPointerOESBounds__IIILjava_nio_Buffer_2I
   (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jobject pointer_buf, jint remaining) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
@@ -2905,12 +3212,18 @@
         (GLvoid *)pointer,
         (GLsizei)remaining
     );
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glWeightPointerOES ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) */
 static void
 android_glWeightPointerOESBounds__IIILjava_nio_Buffer_2I
   (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jobject pointer_buf, jint remaining) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
@@ -2929,6 +3242,9 @@
         (GLvoid *)pointer,
         (GLsizei)remaining
     );
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glDepthRangefOES ( GLclampf zNear, GLclampf zFar ) */
@@ -3016,11 +3332,20 @@
 static void
 android_glClipPlanefOES__ILjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint plane, jobject equation_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *equation = (GLfloat *) 0;
 
+    if (!equation_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "equation == null";
+        goto exit;
+    }
     equation = (GLfloat *)getPointer(_env, equation_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (equation == NULL) {
         char * _equationBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -3030,9 +3355,14 @@
         (GLenum)plane,
         (GLfloat *)equation
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)equation, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glGetClipPlanefOES ( GLenum pname, GLfloat *eqn ) */
@@ -3096,6 +3426,12 @@
     jint _remaining;
     GLfloat *eqn = (GLfloat *) 0;
 
+    if (!eqn_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "eqn == null";
+        goto exit;
+    }
     eqn = (GLfloat *)getPointer(_env, eqn_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 4) {
         _exception = 1;
@@ -3189,11 +3525,20 @@
 static void
 android_glTexGenfvOES__IILjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -3204,9 +3549,14 @@
         (GLenum)pname,
         (GLfloat *)params
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)params, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glTexGeniOES ( GLenum coord, GLenum pname, GLint param ) */
@@ -3268,11 +3618,20 @@
 static void
 android_glTexGenivOES__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -3283,9 +3642,14 @@
         (GLenum)pname,
         (GLint *)params
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)params, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glTexGenxOES ( GLenum coord, GLenum pname, GLfixed param ) */
@@ -3347,11 +3711,20 @@
 static void
 android_glTexGenxvOES__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -3362,9 +3735,14 @@
         (GLenum)pname,
         (GLfixed *)params
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)params, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glGetTexGenfvOES ( GLenum coord, GLenum pname, GLfloat *params ) */
@@ -3415,11 +3793,20 @@
 static void
 android_glGetTexGenfvOES__IILjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -3430,8 +3817,13 @@
         (GLenum)pname,
         (GLfloat *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseFloatArrayElements(_array, (jfloat*)params, 0);
+        _env->ReleaseFloatArrayElements(_array, (jfloat*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -3483,11 +3875,20 @@
 static void
 android_glGetTexGenivOES__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -3498,8 +3899,13 @@
         (GLenum)pname,
         (GLint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -3551,11 +3957,20 @@
 static void
 android_glGetTexGenxvOES__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -3566,8 +3981,13 @@
         (GLenum)pname,
         (GLfixed *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
diff --git a/core/jni/android_opengl_GLES20.cpp b/core/jni/android_opengl_GLES20.cpp
index ac3bf7a..791233b 100644
--- a/core/jni/android_opengl_GLES20.cpp
+++ b/core/jni/android_opengl_GLES20.cpp
@@ -640,6 +640,12 @@
     jint _remaining;
     GLvoid *data = (GLvoid *) 0;
 
+    if (!data_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "data == null";
+        goto exit;
+    }
     data = (GLvoid *)getPointer(_env, data_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < size) {
         _exception = 1;
@@ -742,11 +748,20 @@
 static void
 android_glCompressedTexImage2D__IIIIIIILjava_nio_Buffer_2
   (JNIEnv *_env, jobject _this, jint target, jint level, jint internalformat, jint width, jint height, jint border, jint imageSize, jobject data_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLvoid *data = (GLvoid *) 0;
 
+    if (!data_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "data == null";
+        goto exit;
+    }
     data = (GLvoid *)getPointer(_env, data_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (data == NULL) {
         char * _dataBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
@@ -762,20 +777,34 @@
         (GLsizei)imageSize,
         (GLvoid *)data
     );
+
+exit:
     if (_array) {
         releasePointer(_env, _array, data, JNI_FALSE);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glCompressedTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data ) */
 static void
 android_glCompressedTexSubImage2D__IIIIIIIILjava_nio_Buffer_2
   (JNIEnv *_env, jobject _this, jint target, jint level, jint xoffset, jint yoffset, jint width, jint height, jint format, jint imageSize, jobject data_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLvoid *data = (GLvoid *) 0;
 
+    if (!data_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "data == null";
+        goto exit;
+    }
     data = (GLvoid *)getPointer(_env, data_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (data == NULL) {
         char * _dataBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
@@ -792,9 +821,14 @@
         (GLsizei)imageSize,
         (GLvoid *)data
     );
+
+exit:
     if (_array) {
         releasePointer(_env, _array, data, JNI_FALSE);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glCopyTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border ) */
@@ -919,6 +953,12 @@
     jint _remaining;
     GLuint *buffers = (GLuint *) 0;
 
+    if (!buffers_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "buffers == null";
+        goto exit;
+    }
     buffers = (GLuint *)getPointer(_env, buffers_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -1005,6 +1045,12 @@
     jint _remaining;
     GLuint *framebuffers = (GLuint *) 0;
 
+    if (!framebuffers_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "framebuffers == null";
+        goto exit;
+    }
     framebuffers = (GLuint *)getPointer(_env, framebuffers_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -1100,6 +1146,12 @@
     jint _remaining;
     GLuint *renderbuffers = (GLuint *) 0;
 
+    if (!renderbuffers_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "renderbuffers == null";
+        goto exit;
+    }
     renderbuffers = (GLuint *)getPointer(_env, renderbuffers_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -1195,6 +1247,12 @@
     jint _remaining;
     GLuint *textures = (GLuint *) 0;
 
+    if (!textures_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "textures == null";
+        goto exit;
+    }
     textures = (GLuint *)getPointer(_env, textures_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -1317,6 +1375,12 @@
     jint _remaining;
     GLvoid *indices = (GLvoid *) 0;
 
+    if (!indices_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "indices == null";
+        goto exit;
+    }
     indices = (GLvoid *)getPointer(_env, indices_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < count) {
         _exception = 1;
@@ -1471,6 +1535,12 @@
     jint _remaining;
     GLuint *buffers = (GLuint *) 0;
 
+    if (!buffers_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "buffers == null";
+        goto exit;
+    }
     buffers = (GLuint *)getPointer(_env, buffers_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -1566,6 +1636,12 @@
     jint _remaining;
     GLuint *framebuffers = (GLuint *) 0;
 
+    if (!framebuffers_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "framebuffers == null";
+        goto exit;
+    }
     framebuffers = (GLuint *)getPointer(_env, framebuffers_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -1652,6 +1728,12 @@
     jint _remaining;
     GLuint *renderbuffers = (GLuint *) 0;
 
+    if (!renderbuffers_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "renderbuffers == null";
+        goto exit;
+    }
     renderbuffers = (GLuint *)getPointer(_env, renderbuffers_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -1738,6 +1820,12 @@
     jint _remaining;
     GLuint *textures = (GLuint *) 0;
 
+    if (!textures_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "textures == null";
+        goto exit;
+    }
     textures = (GLuint *)getPointer(_env, textures_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -2514,6 +2602,12 @@
             goto exit;
         }
     }
+    if (!shaders_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "shaders == null";
+        goto exit;
+    }
     shaders = (GLuint *)getPointer(_env, shaders_buf, (jarray*)&_shadersArray, &_shadersRemaining, &_shadersBufferOffset);
     if (_shadersRemaining < maxcount) {
         _exception = 1;
@@ -2659,6 +2753,12 @@
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -2758,11 +2858,20 @@
 static void
 android_glGetFramebufferAttachmentParameteriv__IIILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint attachment, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -2774,8 +2883,13 @@
         (GLenum)pname,
         (GLint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -2856,6 +2970,12 @@
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -2963,6 +3083,12 @@
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -3051,6 +3177,12 @@
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -3084,15 +3216,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;
 }
@@ -3193,6 +3326,12 @@
     jint _precisionRemaining;
     GLint *precision = (GLint *) 0;
 
+    if (!range_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "range == null";
+        goto exit;
+    }
     range = (GLint *)getPointer(_env, range_buf, (jarray*)&_rangeArray, &_rangeRemaining, &_rangeBufferOffset);
     if (_rangeRemaining < 1) {
         _exception = 1;
@@ -3200,6 +3339,12 @@
         _exceptionMessage = "remaining() < 1 < needed";
         goto exit;
     }
+    if (!precision_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "precision == null";
+        goto exit;
+    }
     precision = (GLint *)getPointer(_env, precision_buf, (jarray*)&_precisionArray, &_precisionRemaining, &_precisionBufferOffset);
     if (_precisionRemaining < 1) {
         _exception = 1;
@@ -3408,6 +3553,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -3496,6 +3647,12 @@
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -3584,6 +3741,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -3672,6 +3835,12 @@
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -3805,6 +3974,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -3915,6 +4090,12 @@
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -4081,11 +4262,20 @@
 static void
 android_glReadPixels__IIIIIILjava_nio_Buffer_2
   (JNIEnv *_env, jobject _this, jint x, jint y, jint width, jint height, jint format, jint type, jobject pixels_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLvoid *pixels = (GLvoid *) 0;
 
+    if (!pixels_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "pixels == null";
+        goto exit;
+    }
     pixels = (GLvoid *)getPointer(_env, pixels_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (pixels == NULL) {
         char * _pixelsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
@@ -4100,8 +4290,13 @@
         (GLenum)type,
         (GLvoid *)pixels
     );
+
+exit:
     if (_array) {
-        releasePointer(_env, _array, pixels, JNI_TRUE);
+        releasePointer(_env, _array, pixels, _exception ? JNI_FALSE : JNI_TRUE);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -4178,6 +4373,12 @@
         _env->GetIntArrayElements(shaders_ref, (jboolean *)0);
     shaders = shaders_base + offset;
 
+    if (!binary_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "binary == null";
+        goto exit;
+    }
     binary = (GLvoid *)getPointer(_env, binary_buf, (jarray*)&_array, &_binaryRemaining, &_bufferOffset);
     if (_binaryRemaining < length) {
         _exception = 1;
@@ -4226,7 +4427,19 @@
     jint _binaryRemaining;
     GLvoid *binary = (GLvoid *) 0;
 
+    if (!shaders_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "shaders == null";
+        goto exit;
+    }
     shaders = (GLuint *)getPointer(_env, shaders_buf, (jarray*)&_shadersArray, &_shadersRemaining, &_shadersBufferOffset);
+    if (!binary_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "binary == null";
+        goto exit;
+    }
     binary = (GLvoid *)getPointer(_env, binary_buf, (jarray*)&_binaryArray, &_binaryRemaining, &_binaryBufferOffset);
     if (_binaryRemaining < length) {
         _exception = 1;
@@ -4348,6 +4561,9 @@
 static void
 android_glTexImage2D__IIIIIIIILjava_nio_Buffer_2
   (JNIEnv *_env, jobject _this, jint target, jint level, jint internalformat, jint width, jint height, jint border, jint format, jint type, jobject pixels_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
@@ -4374,6 +4590,9 @@
     if (_array) {
         releasePointer(_env, _array, pixels, JNI_FALSE);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glTexParameterf ( GLenum target, GLenum pname, GLfloat param ) */
@@ -4449,6 +4668,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -4548,6 +4773,12 @@
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -4578,6 +4809,9 @@
 static void
 android_glTexSubImage2D__IIIIIIIILjava_nio_Buffer_2
   (JNIEnv *_env, jobject _this, jint target, jint level, jint xoffset, jint yoffset, jint width, jint height, jint format, jint type, jobject pixels_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
@@ -4604,6 +4838,9 @@
     if (_array) {
         releasePointer(_env, _array, pixels, JNI_FALSE);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glUniform1f ( GLint location, GLfloat x ) */
@@ -4678,6 +4915,12 @@
     jint _remaining;
     GLfloat *v = (GLfloat *) 0;
 
+    if (!v_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "v == null";
+        goto exit;
+    }
     v = (GLfloat *)getPointer(_env, v_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < count) {
         _exception = 1;
@@ -4776,6 +5019,12 @@
     jint _remaining;
     GLint *v = (GLint *) 0;
 
+    if (!v_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "v == null";
+        goto exit;
+    }
     v = (GLint *)getPointer(_env, v_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < count) {
         _exception = 1;
@@ -4875,6 +5124,12 @@
     jint _remaining;
     GLfloat *v = (GLfloat *) 0;
 
+    if (!v_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "v == null";
+        goto exit;
+    }
     v = (GLfloat *)getPointer(_env, v_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < count*2) {
         _exception = 1;
@@ -4974,6 +5229,12 @@
     jint _remaining;
     GLint *v = (GLint *) 0;
 
+    if (!v_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "v == null";
+        goto exit;
+    }
     v = (GLint *)getPointer(_env, v_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < count*2) {
         _exception = 1;
@@ -5074,6 +5335,12 @@
     jint _remaining;
     GLfloat *v = (GLfloat *) 0;
 
+    if (!v_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "v == null";
+        goto exit;
+    }
     v = (GLfloat *)getPointer(_env, v_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < count*3) {
         _exception = 1;
@@ -5174,6 +5441,12 @@
     jint _remaining;
     GLint *v = (GLint *) 0;
 
+    if (!v_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "v == null";
+        goto exit;
+    }
     v = (GLint *)getPointer(_env, v_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < count*3) {
         _exception = 1;
@@ -5275,6 +5548,12 @@
     jint _remaining;
     GLfloat *v = (GLfloat *) 0;
 
+    if (!v_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "v == null";
+        goto exit;
+    }
     v = (GLfloat *)getPointer(_env, v_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < count*4) {
         _exception = 1;
@@ -5376,6 +5655,12 @@
     jint _remaining;
     GLint *v = (GLint *) 0;
 
+    if (!v_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "v == null";
+        goto exit;
+    }
     v = (GLint *)getPointer(_env, v_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < count*4) {
         _exception = 1;
@@ -5465,6 +5750,12 @@
     jint _remaining;
     GLfloat *value = (GLfloat *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLfloat *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < count*4) {
         _exception = 1;
@@ -5555,6 +5846,12 @@
     jint _remaining;
     GLfloat *value = (GLfloat *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLfloat *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < count*9) {
         _exception = 1;
@@ -5645,6 +5942,12 @@
     jint _remaining;
     GLfloat *value = (GLfloat *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLfloat *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < count*16) {
         _exception = 1;
@@ -5761,6 +6064,12 @@
     jint _remaining;
     GLfloat *values = (GLfloat *) 0;
 
+    if (!values_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "values == null";
+        goto exit;
+    }
     values = (GLfloat *)getPointer(_env, values_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -5858,6 +6167,12 @@
     jint _remaining;
     GLfloat *values = (GLfloat *) 0;
 
+    if (!values_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "values == null";
+        goto exit;
+    }
     values = (GLfloat *)getPointer(_env, values_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 2) {
         _exception = 1;
@@ -5956,6 +6271,12 @@
     jint _remaining;
     GLfloat *values = (GLfloat *) 0;
 
+    if (!values_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "values == null";
+        goto exit;
+    }
     values = (GLfloat *)getPointer(_env, values_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 3) {
         _exception = 1;
@@ -6055,6 +6376,12 @@
     jint _remaining;
     GLfloat *values = (GLfloat *) 0;
 
+    if (!values_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "values == null";
+        goto exit;
+    }
     values = (GLfloat *)getPointer(_env, values_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 4) {
         _exception = 1;
@@ -6098,6 +6425,9 @@
 static void
 android_glVertexAttribPointerBounds__IIIZILjava_nio_Buffer_2I
   (JNIEnv *_env, jobject _this, jint indx, jint size, jint type, jboolean normalized, jint stride, jobject ptr_buf, jint remaining) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
@@ -6118,6 +6448,9 @@
         (GLvoid *)ptr,
         (GLsizei)remaining
     );
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glViewport ( GLint x, GLint y, GLsizei width, GLsizei height ) */
diff --git a/core/jni/android_opengl_GLES30.cpp b/core/jni/android_opengl_GLES30.cpp
index 59b8911..736fd99 100644
--- a/core/jni/android_opengl_GLES30.cpp
+++ b/core/jni/android_opengl_GLES30.cpp
@@ -455,11 +455,20 @@
 static void
 android_glDrawRangeElements__IIIIILjava_nio_Buffer_2
   (JNIEnv *_env, jobject _this, jint mode, jint start, jint end, jint count, jint type, jobject indices_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLvoid *indices = (GLvoid *) 0;
 
+    if (!indices_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "indices == null";
+        goto exit;
+    }
     indices = (GLvoid *)getPointer(_env, indices_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (indices == NULL) {
         char * _indicesBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
@@ -473,9 +482,14 @@
         (GLenum)type,
         (GLvoid *)indices
     );
+
+exit:
     if (_array) {
         releasePointer(_env, _array, indices, JNI_FALSE);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glDrawRangeElements ( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLsizei offset ) */
@@ -496,6 +510,9 @@
 static void
 android_glTexImage3D__IIIIIIIIILjava_nio_Buffer_2
   (JNIEnv *_env, jobject _this, jint target, jint level, jint internalformat, jint width, jint height, jint depth, jint border, jint format, jint type, jobject pixels_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
@@ -523,6 +540,9 @@
     if (_array) {
         releasePointer(_env, _array, pixels, JNI_FALSE);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glTexImage3D ( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, GLsizei offset ) */
@@ -547,11 +567,20 @@
 static void
 android_glTexSubImage3D__IIIIIIIIIILjava_nio_Buffer_2
   (JNIEnv *_env, jobject _this, jint target, jint level, jint xoffset, jint yoffset, jint zoffset, jint width, jint height, jint depth, jint format, jint type, jobject pixels_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLvoid *pixels = (GLvoid *) 0;
 
+    if (!pixels_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "pixels == null";
+        goto exit;
+    }
     pixels = (GLvoid *)getPointer(_env, pixels_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (pixels == NULL) {
         char * _pixelsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
@@ -570,9 +599,14 @@
         (GLenum)type,
         (GLvoid *)pixels
     );
+
+exit:
     if (_array) {
         releasePointer(_env, _array, pixels, JNI_FALSE);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glTexSubImage3D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei offset ) */
@@ -615,11 +649,20 @@
 static void
 android_glCompressedTexImage3D__IIIIIIIILjava_nio_Buffer_2
   (JNIEnv *_env, jobject _this, jint target, jint level, jint internalformat, jint width, jint height, jint depth, jint border, jint imageSize, jobject data_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLvoid *data = (GLvoid *) 0;
 
+    if (!data_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "data == null";
+        goto exit;
+    }
     data = (GLvoid *)getPointer(_env, data_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (data == NULL) {
         char * _dataBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
@@ -636,9 +679,14 @@
         (GLsizei)imageSize,
         (GLvoid *)data
     );
+
+exit:
     if (_array) {
         releasePointer(_env, _array, data, JNI_FALSE);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glCompressedTexImage3D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, GLsizei offset ) */
@@ -662,11 +710,20 @@
 static void
 android_glCompressedTexSubImage3D__IIIIIIIIIILjava_nio_Buffer_2
   (JNIEnv *_env, jobject _this, jint target, jint level, jint xoffset, jint yoffset, jint zoffset, jint width, jint height, jint depth, jint format, jint imageSize, jobject data_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLvoid *data = (GLvoid *) 0;
 
+    if (!data_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "data == null";
+        goto exit;
+    }
     data = (GLvoid *)getPointer(_env, data_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (data == NULL) {
         char * _dataBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
@@ -685,9 +742,14 @@
         (GLsizei)imageSize,
         (GLvoid *)data
     );
+
+exit:
     if (_array) {
         releasePointer(_env, _array, data, JNI_FALSE);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glCompressedTexSubImage3D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, GLsizei offset ) */
@@ -756,11 +818,20 @@
 static void
 android_glGenQueries__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint n, jobject ids_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *ids = (GLuint *) 0;
 
+    if (!ids_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "ids == null";
+        goto exit;
+    }
     ids = (GLuint *)getPointer(_env, ids_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (ids == NULL) {
         char * _idsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -770,8 +841,13 @@
         (GLsizei)n,
         (GLuint *)ids
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)ids, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)ids, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -822,11 +898,20 @@
 static void
 android_glDeleteQueries__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint n, jobject ids_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *ids = (GLuint *) 0;
 
+    if (!ids_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "ids == null";
+        goto exit;
+    }
     ids = (GLuint *)getPointer(_env, ids_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (ids == NULL) {
         char * _idsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -836,9 +921,14 @@
         (GLsizei)n,
         (GLuint *)ids
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)ids, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* GLboolean glIsQuery ( GLuint id ) */
@@ -919,11 +1009,20 @@
 static void
 android_glGetQueryiv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -934,8 +1033,13 @@
         (GLenum)pname,
         (GLint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -987,11 +1091,20 @@
 static void
 android_glGetQueryObjectuiv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint id, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *params = (GLuint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLuint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1002,8 +1115,13 @@
         (GLenum)pname,
         (GLuint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -1076,11 +1194,20 @@
 static void
 android_glDrawBuffers__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint n, jobject bufs_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLenum *bufs = (GLenum *) 0;
 
+    if (!bufs_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "bufs == null";
+        goto exit;
+    }
     bufs = (GLenum *)getPointer(_env, bufs_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (bufs == NULL) {
         char * _bufsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1090,9 +1217,14 @@
         (GLsizei)n,
         (GLenum *)bufs
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)bufs, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glUniformMatrix2x3fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
@@ -1144,11 +1276,20 @@
 static void
 android_glUniformMatrix2x3fv__IIZLjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint location, jint count, jboolean transpose, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *value = (GLfloat *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLfloat *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -1160,9 +1301,14 @@
         (GLboolean)transpose,
         (GLfloat *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glUniformMatrix3x2fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
@@ -1214,11 +1360,20 @@
 static void
 android_glUniformMatrix3x2fv__IIZLjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint location, jint count, jboolean transpose, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *value = (GLfloat *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLfloat *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -1230,9 +1385,14 @@
         (GLboolean)transpose,
         (GLfloat *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glUniformMatrix2x4fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
@@ -1284,11 +1444,20 @@
 static void
 android_glUniformMatrix2x4fv__IIZLjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint location, jint count, jboolean transpose, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *value = (GLfloat *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLfloat *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -1300,9 +1469,14 @@
         (GLboolean)transpose,
         (GLfloat *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glUniformMatrix4x2fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
@@ -1354,11 +1528,20 @@
 static void
 android_glUniformMatrix4x2fv__IIZLjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint location, jint count, jboolean transpose, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *value = (GLfloat *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLfloat *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -1370,9 +1553,14 @@
         (GLboolean)transpose,
         (GLfloat *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glUniformMatrix3x4fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
@@ -1424,11 +1612,20 @@
 static void
 android_glUniformMatrix3x4fv__IIZLjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint location, jint count, jboolean transpose, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *value = (GLfloat *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLfloat *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -1440,9 +1637,14 @@
         (GLboolean)transpose,
         (GLfloat *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glUniformMatrix4x3fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
@@ -1494,11 +1696,20 @@
 static void
 android_glUniformMatrix4x3fv__IIZLjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint location, jint count, jboolean transpose, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *value = (GLfloat *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLfloat *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -1510,9 +1721,14 @@
         (GLboolean)transpose,
         (GLfloat *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glBlitFramebuffer ( GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter ) */
@@ -1639,11 +1855,20 @@
 static void
 android_glDeleteVertexArrays__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint n, jobject arrays_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *arrays = (GLuint *) 0;
 
+    if (!arrays_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "arrays == null";
+        goto exit;
+    }
     arrays = (GLuint *)getPointer(_env, arrays_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (arrays == NULL) {
         char * _arraysBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1653,9 +1878,14 @@
         (GLsizei)n,
         (GLuint *)arrays
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)arrays, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glGenVertexArrays ( GLsizei n, GLuint *arrays ) */
@@ -1705,11 +1935,20 @@
 static void
 android_glGenVertexArrays__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint n, jobject arrays_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *arrays = (GLuint *) 0;
 
+    if (!arrays_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "arrays == null";
+        goto exit;
+    }
     arrays = (GLuint *)getPointer(_env, arrays_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (arrays == NULL) {
         char * _arraysBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1719,8 +1958,13 @@
         (GLsizei)n,
         (GLuint *)arrays
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)arrays, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)arrays, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -1783,11 +2027,20 @@
 static void
 android_glGetIntegeri_v__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint index, jobject data_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *data = (GLint *) 0;
 
+    if (!data_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "data == null";
+        goto exit;
+    }
     data = (GLint *)getPointer(_env, data_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (data == NULL) {
         char * _dataBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1798,8 +2051,13 @@
         (GLuint)index,
         (GLint *)data
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)data, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)data, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -2240,6 +2498,9 @@
 static void
 android_glVertexAttribIPointerBounds__IIIILjava_nio_Buffer_2I
   (JNIEnv *_env, jobject _this, jint index, jint size, jint type, jint stride, jobject pointer_buf, jint remaining) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
@@ -2259,6 +2520,9 @@
         (GLvoid *)pointer,
         (GLsizei)remaining
     );
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glVertexAttribIPointer ( GLuint index, GLint size, GLenum type, GLsizei stride, GLsizei offset ) */
@@ -2322,11 +2586,20 @@
 static void
 android_glGetVertexAttribIiv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint index, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -2337,8 +2610,13 @@
         (GLenum)pname,
         (GLint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -2390,11 +2668,20 @@
 static void
 android_glGetVertexAttribIuiv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint index, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *params = (GLuint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLuint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -2405,8 +2692,13 @@
         (GLenum)pname,
         (GLuint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -2483,11 +2775,20 @@
 static void
 android_glVertexAttribI4iv__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint index, jobject v_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *v = (GLint *) 0;
 
+    if (!v_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "v == null";
+        goto exit;
+    }
     v = (GLint *)getPointer(_env, v_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (v == NULL) {
         char * _vBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -2497,9 +2798,14 @@
         (GLuint)index,
         (GLint *)v
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)v, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glVertexAttribI4uiv ( GLuint index, const GLuint *v ) */
@@ -2549,11 +2855,20 @@
 static void
 android_glVertexAttribI4uiv__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint index, jobject v_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *v = (GLuint *) 0;
 
+    if (!v_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "v == null";
+        goto exit;
+    }
     v = (GLuint *)getPointer(_env, v_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (v == NULL) {
         char * _vBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -2563,9 +2878,14 @@
         (GLuint)index,
         (GLuint *)v
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)v, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glGetUniformuiv ( GLuint program, GLint location, GLuint *params ) */
@@ -2616,11 +2936,20 @@
 static void
 android_glGetUniformuiv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint location, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *params = (GLuint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLuint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -2631,8 +2960,13 @@
         (GLint)location,
         (GLuint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -2764,11 +3098,20 @@
 static void
 android_glUniform1uiv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint location, jint count, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *value = (GLuint *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLuint *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -2779,9 +3122,14 @@
         (GLsizei)count,
         (GLuint *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glUniform2uiv ( GLint location, GLsizei count, const GLuint *value ) */
@@ -2832,11 +3180,20 @@
 static void
 android_glUniform2uiv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint location, jint count, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *value = (GLuint *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLuint *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -2847,9 +3204,14 @@
         (GLsizei)count,
         (GLuint *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glUniform3uiv ( GLint location, GLsizei count, const GLuint *value ) */
@@ -2900,11 +3262,20 @@
 static void
 android_glUniform3uiv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint location, jint count, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *value = (GLuint *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLuint *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -2915,9 +3286,14 @@
         (GLsizei)count,
         (GLuint *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glUniform4uiv ( GLint location, GLsizei count, const GLuint *value ) */
@@ -2968,11 +3344,20 @@
 static void
 android_glUniform4uiv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint location, jint count, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *value = (GLuint *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLuint *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -2983,9 +3368,14 @@
         (GLsizei)count,
         (GLuint *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glClearBufferiv ( GLenum buffer, GLint drawbuffer, const GLint *value ) */
@@ -3036,11 +3426,20 @@
 static void
 android_glClearBufferiv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint buffer, jint drawbuffer, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *value = (GLint *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLint *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -3051,9 +3450,14 @@
         (GLint)drawbuffer,
         (GLint *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glClearBufferuiv ( GLenum buffer, GLint drawbuffer, const GLuint *value ) */
@@ -3104,11 +3508,20 @@
 static void
 android_glClearBufferuiv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint buffer, jint drawbuffer, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *value = (GLuint *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLuint *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -3119,9 +3532,14 @@
         (GLint)drawbuffer,
         (GLuint *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glClearBufferfv ( GLenum buffer, GLint drawbuffer, const GLfloat *value ) */
@@ -3172,11 +3590,20 @@
 static void
 android_glClearBufferfv__IILjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint buffer, jint drawbuffer, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *value = (GLfloat *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLfloat *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -3187,9 +3614,14 @@
         (GLint)drawbuffer,
         (GLfloat *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glClearBufferfi ( GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil ) */
@@ -3453,6 +3885,9 @@
 static void
 android_glGetActiveUniformsiv__IILjava_nio_IntBuffer_2ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint uniformCount, jobject uniformIndices_buf, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _uniformIndicesArray = (jintArray) 0;
     jint _uniformIndicesBufferOffset = (jint) 0;
     jintArray _paramsArray = (jintArray) 0;
@@ -3462,7 +3897,19 @@
     jint _paramsRemaining;
     GLint *params = (GLint *) 0;
 
+    if (!uniformIndices_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "uniformIndices == null";
+        goto exit;
+    }
     uniformIndices = (GLuint *)getPointer(_env, uniformIndices_buf, (jarray*)&_uniformIndicesArray, &_uniformIndicesRemaining, &_uniformIndicesBufferOffset);
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_paramsArray, &_paramsRemaining, &_paramsBufferOffset);
     if (uniformIndices == NULL) {
         char * _uniformIndicesBase = (char *)_env->GetIntArrayElements(_uniformIndicesArray, (jboolean *) 0);
@@ -3479,12 +3926,17 @@
         (GLenum)pname,
         (GLint *)params
     );
+
+exit:
     if (_paramsArray) {
-        _env->ReleaseIntArrayElements(_paramsArray, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_paramsArray, (jint*)params, _exception ? JNI_ABORT : 0);
     }
     if (_uniformIndicesArray) {
         _env->ReleaseIntArrayElements(_uniformIndicesArray, (jint*)uniformIndices, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* GLuint glGetUniformBlockIndex ( GLuint program, const GLchar *uniformBlockName ) */
@@ -3570,11 +4022,20 @@
 static void
 android_glGetActiveUniformBlockiv__IIILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint uniformBlockIndex, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -3586,8 +4047,13 @@
         (GLenum)pname,
         (GLint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -3877,11 +4343,20 @@
 static void
 android_glGetInteger64v__ILjava_nio_LongBuffer_2
   (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jlongArray _array = (jlongArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint64 *params = (GLint64 *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint64 *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetLongArrayElements(_array, (jboolean *) 0);
@@ -3891,8 +4366,13 @@
         (GLenum)pname,
         (GLint64 *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseLongArrayElements(_array, (jlong*)params, 0);
+        _env->ReleaseLongArrayElements(_array, (jlong*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -3966,6 +4446,9 @@
 static void
 android_glGetSynciv__JIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jlong sync, jint pname, jint bufSize, jobject length_buf, jobject values_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _lengthArray = (jintArray) 0;
     jint _lengthBufferOffset = (jint) 0;
     jintArray _valuesArray = (jintArray) 0;
@@ -3978,6 +4461,12 @@
     if (length_buf) {
         length = (GLsizei *)getPointer(_env, length_buf, (jarray*)&_lengthArray, &_lengthRemaining, &_lengthBufferOffset);
     }
+    if (!values_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "values == null";
+        goto exit;
+    }
     values = (GLint *)getPointer(_env, values_buf, (jarray*)&_valuesArray, &_valuesRemaining, &_valuesBufferOffset);
     if (length_buf && length == NULL) {
         char * _lengthBase = (char *)_env->GetIntArrayElements(_lengthArray, (jboolean *) 0);
@@ -3994,11 +4483,16 @@
         (GLsizei *)length,
         (GLint *)values
     );
+
+exit:
     if (_valuesArray) {
-        _env->ReleaseIntArrayElements(_valuesArray, (jint*)values, 0);
+        _env->ReleaseIntArrayElements(_valuesArray, (jint*)values, _exception ? JNI_ABORT : 0);
     }
     if (_lengthArray) {
-        _env->ReleaseIntArrayElements(_lengthArray, (jint*)length, 0);
+        _env->ReleaseIntArrayElements(_lengthArray, (jint*)length, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -4050,11 +4544,20 @@
 static void
 android_glGetInteger64i_v__IILjava_nio_LongBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint index, jobject data_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jlongArray _array = (jlongArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint64 *data = (GLint64 *) 0;
 
+    if (!data_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "data == null";
+        goto exit;
+    }
     data = (GLint64 *)getPointer(_env, data_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (data == NULL) {
         char * _dataBase = (char *)_env->GetLongArrayElements(_array, (jboolean *) 0);
@@ -4065,8 +4568,13 @@
         (GLuint)index,
         (GLint64 *)data
     );
+
+exit:
     if (_array) {
-        _env->ReleaseLongArrayElements(_array, (jlong*)data, 0);
+        _env->ReleaseLongArrayElements(_array, (jlong*)data, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -4118,11 +4626,20 @@
 static void
 android_glGetBufferParameteri64v__IILjava_nio_LongBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jlongArray _array = (jlongArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint64 *params = (GLint64 *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint64 *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetLongArrayElements(_array, (jboolean *) 0);
@@ -4133,8 +4650,13 @@
         (GLenum)pname,
         (GLint64 *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseLongArrayElements(_array, (jlong*)params, 0);
+        _env->ReleaseLongArrayElements(_array, (jlong*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -4185,11 +4707,20 @@
 static void
 android_glGenSamplers__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint count, jobject samplers_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *samplers = (GLuint *) 0;
 
+    if (!samplers_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "samplers == null";
+        goto exit;
+    }
     samplers = (GLuint *)getPointer(_env, samplers_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (samplers == NULL) {
         char * _samplersBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -4199,8 +4730,13 @@
         (GLsizei)count,
         (GLuint *)samplers
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)samplers, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)samplers, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -4251,11 +4787,20 @@
 static void
 android_glDeleteSamplers__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint count, jobject samplers_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *samplers = (GLuint *) 0;
 
+    if (!samplers_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "samplers == null";
+        goto exit;
+    }
     samplers = (GLuint *)getPointer(_env, samplers_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (samplers == NULL) {
         char * _samplersBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -4265,9 +4810,14 @@
         (GLsizei)count,
         (GLuint *)samplers
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)samplers, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* GLboolean glIsSampler ( GLuint sampler ) */
@@ -4350,11 +4900,20 @@
 static void
 android_glSamplerParameteriv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject param_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *param = (GLint *) 0;
 
+    if (!param_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "param == null";
+        goto exit;
+    }
     param = (GLint *)getPointer(_env, param_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (param == NULL) {
         char * _paramBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -4365,9 +4924,14 @@
         (GLenum)pname,
         (GLint *)param
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)param, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glSamplerParameterf ( GLuint sampler, GLenum pname, GLfloat param ) */
@@ -4429,11 +4993,20 @@
 static void
 android_glSamplerParameterfv__IILjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject param_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *param = (GLfloat *) 0;
 
+    if (!param_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "param == null";
+        goto exit;
+    }
     param = (GLfloat *)getPointer(_env, param_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (param == NULL) {
         char * _paramBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -4444,9 +5017,14 @@
         (GLenum)pname,
         (GLfloat *)param
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)param, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glGetSamplerParameteriv ( GLuint sampler, GLenum pname, GLint *params ) */
@@ -4497,11 +5075,20 @@
 static void
 android_glGetSamplerParameteriv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -4512,8 +5099,13 @@
         (GLenum)pname,
         (GLint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -4565,11 +5157,20 @@
 static void
 android_glGetSamplerParameterfv__IILjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -4580,8 +5181,13 @@
         (GLenum)pname,
         (GLfloat *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseFloatArrayElements(_array, (jfloat*)params, 0);
+        _env->ReleaseFloatArrayElements(_array, (jfloat*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -4652,11 +5258,20 @@
 static void
 android_glDeleteTransformFeedbacks__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint n, jobject ids_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *ids = (GLuint *) 0;
 
+    if (!ids_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "ids == null";
+        goto exit;
+    }
     ids = (GLuint *)getPointer(_env, ids_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (ids == NULL) {
         char * _idsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -4666,9 +5281,14 @@
         (GLsizei)n,
         (GLuint *)ids
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)ids, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glGenTransformFeedbacks ( GLsizei n, GLuint *ids ) */
@@ -4718,11 +5338,20 @@
 static void
 android_glGenTransformFeedbacks__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint n, jobject ids_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *ids = (GLuint *) 0;
 
+    if (!ids_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "ids == null";
+        goto exit;
+    }
     ids = (GLuint *)getPointer(_env, ids_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (ids == NULL) {
         char * _idsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -4732,8 +5361,13 @@
         (GLsizei)n,
         (GLuint *)ids
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)ids, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)ids, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -4810,6 +5444,12 @@
         _env->GetIntArrayElements(binaryFormat_ref, (jboolean *)0);
     binaryFormat = binaryFormat_base + binaryFormatOffset;
 
+    if (!binary_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "binary == null";
+        goto exit;
+    }
     binary = (GLvoid *)getPointer(_env, binary_buf, (jarray*)&_array, &_binaryRemaining, &_bufferOffset);
     if (binary == NULL) {
         char * _binaryBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
@@ -4844,6 +5484,9 @@
 static void
 android_glGetProgramBinary__IILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_Buffer_2
   (JNIEnv *_env, jobject _this, jint program, jint bufSize, jobject length_buf, jobject binaryFormat_buf, jobject binary_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _lengthArray = (jintArray) 0;
     jint _lengthBufferOffset = (jint) 0;
     jintArray _binaryFormatArray = (jintArray) 0;
@@ -4860,7 +5503,19 @@
     if (length_buf) {
         length = (GLsizei *)getPointer(_env, length_buf, (jarray*)&_lengthArray, &_lengthRemaining, &_lengthBufferOffset);
     }
+    if (!binaryFormat_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "binaryFormat == null";
+        goto exit;
+    }
     binaryFormat = (GLenum *)getPointer(_env, binaryFormat_buf, (jarray*)&_binaryFormatArray, &_binaryFormatRemaining, &_binaryFormatBufferOffset);
+    if (!binary_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "binary == null";
+        goto exit;
+    }
     binary = (GLvoid *)getPointer(_env, binary_buf, (jarray*)&_binaryArray, &_binaryRemaining, &_binaryBufferOffset);
     if (length_buf && length == NULL) {
         char * _lengthBase = (char *)_env->GetIntArrayElements(_lengthArray, (jboolean *) 0);
@@ -4881,14 +5536,19 @@
         (GLenum *)binaryFormat,
         (GLvoid *)binary
     );
+
+exit:
     if (_binaryArray) {
-        releasePointer(_env, _binaryArray, binary, JNI_TRUE);
+        releasePointer(_env, _binaryArray, binary, _exception ? JNI_FALSE : JNI_TRUE);
     }
     if (_binaryFormatArray) {
-        _env->ReleaseIntArrayElements(_binaryFormatArray, (jint*)binaryFormat, 0);
+        _env->ReleaseIntArrayElements(_binaryFormatArray, (jint*)binaryFormat, _exception ? JNI_ABORT : 0);
     }
     if (_lengthArray) {
-        _env->ReleaseIntArrayElements(_lengthArray, (jint*)length, 0);
+        _env->ReleaseIntArrayElements(_lengthArray, (jint*)length, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -4896,11 +5556,20 @@
 static void
 android_glProgramBinary__IILjava_nio_Buffer_2I
   (JNIEnv *_env, jobject _this, jint program, jint binaryFormat, jobject binary_buf, jint length) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLvoid *binary = (GLvoid *) 0;
 
+    if (!binary_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "binary == null";
+        goto exit;
+    }
     binary = (GLvoid *)getPointer(_env, binary_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (binary == NULL) {
         char * _binaryBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
@@ -4912,9 +5581,14 @@
         (GLvoid *)binary,
         (GLsizei)length
     );
+
+exit:
     if (_array) {
         releasePointer(_env, _array, binary, JNI_FALSE);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glProgramParameteri ( GLuint program, GLenum pname, GLint value ) */
@@ -4976,11 +5650,20 @@
 static void
 android_glInvalidateFramebuffer__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint numAttachments, jobject attachments_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLenum *attachments = (GLenum *) 0;
 
+    if (!attachments_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "attachments == null";
+        goto exit;
+    }
     attachments = (GLenum *)getPointer(_env, attachments_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (attachments == NULL) {
         char * _attachmentsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -4991,9 +5674,14 @@
         (GLsizei)numAttachments,
         (GLenum *)attachments
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)attachments, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glInvalidateSubFramebuffer ( GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height ) */
@@ -5048,11 +5736,20 @@
 static void
 android_glInvalidateSubFramebuffer__IILjava_nio_IntBuffer_2IIII
   (JNIEnv *_env, jobject _this, jint target, jint numAttachments, jobject attachments_buf, jint x, jint y, jint width, jint height) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLenum *attachments = (GLenum *) 0;
 
+    if (!attachments_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "attachments == null";
+        goto exit;
+    }
     attachments = (GLenum *)getPointer(_env, attachments_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (attachments == NULL) {
         char * _attachmentsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -5067,9 +5764,14 @@
         (GLsizei)width,
         (GLsizei)height
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)attachments, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glTexStorage2D ( GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height ) */
@@ -5149,11 +5851,20 @@
 static void
 android_glGetInternalformativ__IIIILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint internalformat, jint pname, jint bufSize, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -5166,8 +5877,13 @@
         (GLsizei)bufSize,
         (GLint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
diff --git a/core/jni/android_opengl_GLES31.cpp b/core/jni/android_opengl_GLES31.cpp
index 156e7bd..0e596dc 100644
--- a/core/jni/android_opengl_GLES31.cpp
+++ b/core/jni/android_opengl_GLES31.cpp
@@ -547,11 +547,20 @@
 static void
 android_glGetFramebufferParameteriv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -562,8 +571,13 @@
         (GLenum)pname,
         (GLint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -616,11 +630,20 @@
 static void
 android_glGetProgramInterfaceiv__IIILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint programInterface, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -632,8 +655,13 @@
         (GLenum)pname,
         (GLint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -777,6 +805,9 @@
 static void
 android_glGetProgramResourceiv__IIIILjava_nio_IntBuffer_2ILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint programInterface, jint index, jint propCount, jobject props_buf, jint bufSize, jobject length_buf, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _propsArray = (jintArray) 0;
     jint _propsBufferOffset = (jint) 0;
     jintArray _lengthArray = (jintArray) 0;
@@ -790,10 +821,22 @@
     jint _paramsRemaining;
     GLint *params = (GLint *) 0;
 
+    if (!props_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "props == null";
+        goto exit;
+    }
     props = (GLenum *)getPointer(_env, props_buf, (jarray*)&_propsArray, &_propsRemaining, &_propsBufferOffset);
     if (length_buf) {
         length = (GLsizei *)getPointer(_env, length_buf, (jarray*)&_lengthArray, &_lengthRemaining, &_lengthBufferOffset);
     }
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_paramsArray, &_paramsRemaining, &_paramsBufferOffset);
     if (props == NULL) {
         char * _propsBase = (char *)_env->GetIntArrayElements(_propsArray, (jboolean *) 0);
@@ -817,15 +860,20 @@
         (GLsizei *)length,
         (GLint *)params
     );
+
+exit:
     if (_paramsArray) {
-        _env->ReleaseIntArrayElements(_paramsArray, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_paramsArray, (jint*)params, _exception ? JNI_ABORT : 0);
     }
     if (_lengthArray) {
-        _env->ReleaseIntArrayElements(_lengthArray, (jint*)length, 0);
+        _env->ReleaseIntArrayElements(_lengthArray, (jint*)length, _exception ? JNI_ABORT : 0);
     }
     if (_propsArray) {
         _env->ReleaseIntArrayElements(_propsArray, (jint*)props, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* GLint glGetProgramResourceLocation ( GLuint program, GLenum programInterface, const GLchar *name ) */
@@ -1008,11 +1056,20 @@
 static void
 android_glDeleteProgramPipelines__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint n, jobject pipelines_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *pipelines = (GLuint *) 0;
 
+    if (!pipelines_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "pipelines == null";
+        goto exit;
+    }
     pipelines = (GLuint *)getPointer(_env, pipelines_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (pipelines == NULL) {
         char * _pipelinesBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1022,9 +1079,14 @@
         (GLsizei)n,
         (GLuint *)pipelines
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)pipelines, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glGenProgramPipelines ( GLsizei n, GLuint *pipelines ) */
@@ -1074,11 +1136,20 @@
 static void
 android_glGenProgramPipelines__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint n, jobject pipelines_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *pipelines = (GLuint *) 0;
 
+    if (!pipelines_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "pipelines == null";
+        goto exit;
+    }
     pipelines = (GLuint *)getPointer(_env, pipelines_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (pipelines == NULL) {
         char * _pipelinesBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1088,8 +1159,13 @@
         (GLsizei)n,
         (GLuint *)pipelines
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)pipelines, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)pipelines, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -1152,11 +1228,20 @@
 static void
 android_glGetProgramPipelineiv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint pipeline, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1167,8 +1252,13 @@
         (GLenum)pname,
         (GLint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -1371,11 +1461,20 @@
 static void
 android_glProgramUniform1iv__IIILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint location, jint count, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *value = (GLint *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLint *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1387,9 +1486,14 @@
         (GLsizei)count,
         (GLint *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glProgramUniform2iv ( GLuint program, GLint location, GLsizei count, const GLint *value ) */
@@ -1441,11 +1545,20 @@
 static void
 android_glProgramUniform2iv__IIILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint location, jint count, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *value = (GLint *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLint *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1457,9 +1570,14 @@
         (GLsizei)count,
         (GLint *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glProgramUniform3iv ( GLuint program, GLint location, GLsizei count, const GLint *value ) */
@@ -1511,11 +1629,20 @@
 static void
 android_glProgramUniform3iv__IIILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint location, jint count, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *value = (GLint *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLint *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1527,9 +1654,14 @@
         (GLsizei)count,
         (GLint *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glProgramUniform4iv ( GLuint program, GLint location, GLsizei count, const GLint *value ) */
@@ -1581,11 +1713,20 @@
 static void
 android_glProgramUniform4iv__IIILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint location, jint count, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *value = (GLint *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLint *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1597,9 +1738,14 @@
         (GLsizei)count,
         (GLint *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glProgramUniform1uiv ( GLuint program, GLint location, GLsizei count, const GLuint *value ) */
@@ -1651,11 +1797,20 @@
 static void
 android_glProgramUniform1uiv__IIILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint location, jint count, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *value = (GLuint *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLuint *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1667,9 +1822,14 @@
         (GLsizei)count,
         (GLuint *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glProgramUniform2uiv ( GLuint program, GLint location, GLsizei count, const GLuint *value ) */
@@ -1721,11 +1881,20 @@
 static void
 android_glProgramUniform2uiv__IIILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint location, jint count, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *value = (GLuint *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLuint *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1737,9 +1906,14 @@
         (GLsizei)count,
         (GLuint *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glProgramUniform3uiv ( GLuint program, GLint location, GLsizei count, const GLuint *value ) */
@@ -1791,11 +1965,20 @@
 static void
 android_glProgramUniform3uiv__IIILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint location, jint count, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *value = (GLuint *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLuint *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1807,9 +1990,14 @@
         (GLsizei)count,
         (GLuint *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glProgramUniform4uiv ( GLuint program, GLint location, GLsizei count, const GLuint *value ) */
@@ -1861,11 +2049,20 @@
 static void
 android_glProgramUniform4uiv__IIILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint location, jint count, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *value = (GLuint *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLuint *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1877,9 +2074,14 @@
         (GLsizei)count,
         (GLuint *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glProgramUniform1fv ( GLuint program, GLint location, GLsizei count, const GLfloat *value ) */
@@ -1931,11 +2133,20 @@
 static void
 android_glProgramUniform1fv__IIILjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint location, jint count, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *value = (GLfloat *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLfloat *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -1947,9 +2158,14 @@
         (GLsizei)count,
         (GLfloat *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glProgramUniform2fv ( GLuint program, GLint location, GLsizei count, const GLfloat *value ) */
@@ -2001,11 +2217,20 @@
 static void
 android_glProgramUniform2fv__IIILjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint location, jint count, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *value = (GLfloat *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLfloat *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -2017,9 +2242,14 @@
         (GLsizei)count,
         (GLfloat *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glProgramUniform3fv ( GLuint program, GLint location, GLsizei count, const GLfloat *value ) */
@@ -2071,11 +2301,20 @@
 static void
 android_glProgramUniform3fv__IIILjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint location, jint count, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *value = (GLfloat *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLfloat *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -2087,9 +2326,14 @@
         (GLsizei)count,
         (GLfloat *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glProgramUniform4fv ( GLuint program, GLint location, GLsizei count, const GLfloat *value ) */
@@ -2141,11 +2385,20 @@
 static void
 android_glProgramUniform4fv__IIILjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint location, jint count, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *value = (GLfloat *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLfloat *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -2157,9 +2410,14 @@
         (GLsizei)count,
         (GLfloat *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glProgramUniformMatrix2fv ( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
@@ -2212,11 +2470,20 @@
 static void
 android_glProgramUniformMatrix2fv__IIIZLjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint location, jint count, jboolean transpose, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *value = (GLfloat *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLfloat *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -2229,9 +2496,14 @@
         (GLboolean)transpose,
         (GLfloat *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glProgramUniformMatrix3fv ( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
@@ -2284,11 +2556,20 @@
 static void
 android_glProgramUniformMatrix3fv__IIIZLjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint location, jint count, jboolean transpose, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *value = (GLfloat *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLfloat *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -2301,9 +2582,14 @@
         (GLboolean)transpose,
         (GLfloat *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glProgramUniformMatrix4fv ( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
@@ -2356,11 +2642,20 @@
 static void
 android_glProgramUniformMatrix4fv__IIIZLjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint location, jint count, jboolean transpose, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *value = (GLfloat *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLfloat *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -2373,9 +2668,14 @@
         (GLboolean)transpose,
         (GLfloat *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glProgramUniformMatrix2x3fv ( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
@@ -2428,11 +2728,20 @@
 static void
 android_glProgramUniformMatrix2x3fv__IIIZLjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint location, jint count, jboolean transpose, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *value = (GLfloat *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLfloat *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -2445,9 +2754,14 @@
         (GLboolean)transpose,
         (GLfloat *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glProgramUniformMatrix3x2fv ( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
@@ -2500,11 +2814,20 @@
 static void
 android_glProgramUniformMatrix3x2fv__IIIZLjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint location, jint count, jboolean transpose, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *value = (GLfloat *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLfloat *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -2517,9 +2840,14 @@
         (GLboolean)transpose,
         (GLfloat *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glProgramUniformMatrix2x4fv ( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
@@ -2572,11 +2900,20 @@
 static void
 android_glProgramUniformMatrix2x4fv__IIIZLjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint location, jint count, jboolean transpose, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *value = (GLfloat *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLfloat *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -2589,9 +2926,14 @@
         (GLboolean)transpose,
         (GLfloat *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glProgramUniformMatrix4x2fv ( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
@@ -2644,11 +2986,20 @@
 static void
 android_glProgramUniformMatrix4x2fv__IIIZLjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint location, jint count, jboolean transpose, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *value = (GLfloat *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLfloat *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -2661,9 +3012,14 @@
         (GLboolean)transpose,
         (GLfloat *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glProgramUniformMatrix3x4fv ( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
@@ -2716,11 +3072,20 @@
 static void
 android_glProgramUniformMatrix3x4fv__IIIZLjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint location, jint count, jboolean transpose, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *value = (GLfloat *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLfloat *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -2733,9 +3098,14 @@
         (GLboolean)transpose,
         (GLfloat *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glProgramUniformMatrix4x3fv ( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
@@ -2788,11 +3158,20 @@
 static void
 android_glProgramUniformMatrix4x3fv__IIIZLjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint program, jint location, jint count, jboolean transpose, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *value = (GLfloat *) 0;
 
+    if (!value_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
     value = (GLfloat *)getPointer(_env, value_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (value == NULL) {
         char * _valueBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -2805,9 +3184,14 @@
         (GLboolean)transpose,
         (GLfloat *)value
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)value, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glValidateProgramPipeline ( GLuint pipeline ) */
@@ -2901,11 +3285,20 @@
 static void
 android_glGetBooleani_v__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint index, jobject data_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLboolean *data = (GLboolean *) 0;
 
+    if (!data_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "data == null";
+        goto exit;
+    }
     data = (GLboolean *)getPointer(_env, data_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (data == NULL) {
         char * _dataBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -2916,8 +3309,13 @@
         (GLuint)index,
         (GLboolean *)data
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)data, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)data, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -3001,11 +3399,20 @@
 static void
 android_glGetMultisamplefv__IILjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint pname, jint index, jobject val_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *val = (GLfloat *) 0;
 
+    if (!val_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "val == null";
+        goto exit;
+    }
     val = (GLfloat *)getPointer(_env, val_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (val == NULL) {
         char * _valBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -3016,8 +3423,13 @@
         (GLuint)index,
         (GLfloat *)val
     );
+
+exit:
     if (_array) {
-        _env->ReleaseFloatArrayElements(_array, (jfloat*)val, 0);
+        _env->ReleaseFloatArrayElements(_array, (jfloat*)val, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -3080,11 +3492,20 @@
 static void
 android_glGetTexLevelParameteriv__IIILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint level, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -3096,8 +3517,13 @@
         (GLenum)pname,
         (GLint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -3150,11 +3576,20 @@
 static void
 android_glGetTexLevelParameterfv__IIILjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint level, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -3166,8 +3601,13 @@
         (GLenum)pname,
         (GLfloat *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseFloatArrayElements(_array, (jfloat*)params, 0);
+        _env->ReleaseFloatArrayElements(_array, (jfloat*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
diff --git a/core/jni/android_opengl_GLES31Ext.cpp b/core/jni/android_opengl_GLES31Ext.cpp
index 5be7be0..9f2b0c5 100644
--- a/core/jni/android_opengl_GLES31Ext.cpp
+++ b/core/jni/android_opengl_GLES31Ext.cpp
@@ -499,11 +499,20 @@
 static void
 android_glDebugMessageControlKHR__IIIILjava_nio_IntBuffer_2Z
   (JNIEnv *_env, jobject _this, jint source, jint type, jint severity, jint count, jobject ids_buf, jboolean enabled) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *ids = (GLuint *) 0;
 
+    if (!ids_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "ids == null";
+        goto exit;
+    }
     ids = (GLuint *)getPointer(_env, ids_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (ids == NULL) {
         char * _idsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -517,9 +526,14 @@
         (GLuint *)ids,
         (GLboolean)enabled
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)ids, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glDebugMessageInsertKHR ( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf ) */
@@ -915,11 +929,20 @@
 static void
 android_glTexParameterIivEXT__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -930,9 +953,14 @@
         (GLenum)pname,
         (GLint *)params
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)params, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glTexParameterIuivEXT ( GLenum target, GLenum pname, const GLuint *params ) */
@@ -983,11 +1011,20 @@
 static void
 android_glTexParameterIuivEXT__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *params = (GLuint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLuint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -998,9 +1035,14 @@
         (GLenum)pname,
         (GLuint *)params
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)params, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glGetTexParameterIivEXT ( GLenum target, GLenum pname, GLint *params ) */
@@ -1051,11 +1093,20 @@
 static void
 android_glGetTexParameterIivEXT__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1066,8 +1117,13 @@
         (GLenum)pname,
         (GLint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -1119,11 +1175,20 @@
 static void
 android_glGetTexParameterIuivEXT__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *params = (GLuint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLuint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1134,8 +1199,13 @@
         (GLenum)pname,
         (GLuint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -1187,11 +1257,20 @@
 static void
 android_glSamplerParameterIivEXT__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject param_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *param = (GLint *) 0;
 
+    if (!param_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "param == null";
+        goto exit;
+    }
     param = (GLint *)getPointer(_env, param_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (param == NULL) {
         char * _paramBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1202,9 +1281,14 @@
         (GLenum)pname,
         (GLint *)param
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)param, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glSamplerParameterIuivEXT ( GLuint sampler, GLenum pname, const GLuint *param ) */
@@ -1255,11 +1339,20 @@
 static void
 android_glSamplerParameterIuivEXT__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject param_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *param = (GLuint *) 0;
 
+    if (!param_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "param == null";
+        goto exit;
+    }
     param = (GLuint *)getPointer(_env, param_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (param == NULL) {
         char * _paramBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1270,9 +1363,14 @@
         (GLenum)pname,
         (GLuint *)param
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)param, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glGetSamplerParameterIivEXT ( GLuint sampler, GLenum pname, GLint *params ) */
@@ -1323,11 +1421,20 @@
 static void
 android_glGetSamplerParameterIivEXT__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1338,8 +1445,13 @@
         (GLenum)pname,
         (GLint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -1391,11 +1503,20 @@
 static void
 android_glGetSamplerParameterIuivEXT__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *params = (GLuint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLuint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1406,8 +1527,13 @@
         (GLenum)pname,
         (GLuint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
diff --git a/core/jni/android_opengl_GLES32.cpp b/core/jni/android_opengl_GLES32.cpp
index f9a1a8e..aa917a0 100644
--- a/core/jni/android_opengl_GLES32.cpp
+++ b/core/jni/android_opengl_GLES32.cpp
@@ -535,6 +535,12 @@
     jint _remaining;
     GLuint *ids = (GLuint *) 0;
 
+    if (!ids_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "ids == null";
+        goto exit;
+    }
     ids = (GLuint *)getPointer(_env, ids_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < count) {
         _exception = 1;
@@ -852,6 +858,12 @@
     jint _remaining;
     void *indices = (void *) 0;
 
+    if (!indices_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "indices == null";
+        goto exit;
+    }
     indices = (void *)getPointer(_env, indices_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < count-basevertex) {
         _exception = 1;
@@ -892,6 +904,12 @@
     jint _remaining;
     void *indices = (void *) 0;
 
+    if (!indices_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "indices == null";
+        goto exit;
+    }
     indices = (void *)getPointer(_env, indices_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < count-basevertex) {
         _exception = 1;
@@ -1022,6 +1040,12 @@
     jint _remaining;
     void *data = (void *) 0;
 
+    if (!data_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "data == null";
+        goto exit;
+    }
     data = (void *)getPointer(_env, data_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < bufSize) {
         _exception = 1;
@@ -1116,6 +1140,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < bufSize) {
         _exception = 1;
@@ -1206,6 +1236,12 @@
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < bufSize) {
         _exception = 1;
@@ -1296,6 +1332,12 @@
     jint _remaining;
     GLuint *params = (GLuint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLuint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < bufSize) {
         _exception = 1;
@@ -1390,11 +1432,20 @@
 static void
 android_glTexParameterIiv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1405,9 +1456,14 @@
         (GLenum)pname,
         (GLint *)params
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)params, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glTexParameterIuiv ( GLenum target, GLenum pname, const GLuint *params ) */
@@ -1458,11 +1514,20 @@
 static void
 android_glTexParameterIuiv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *params = (GLuint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLuint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1473,9 +1538,14 @@
         (GLenum)pname,
         (GLuint *)params
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)params, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glGetTexParameterIiv ( GLenum target, GLenum pname, GLint *params ) */
@@ -1526,11 +1596,20 @@
 static void
 android_glGetTexParameterIiv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1541,8 +1620,13 @@
         (GLenum)pname,
         (GLint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -1594,11 +1678,20 @@
 static void
 android_glGetTexParameterIuiv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *params = (GLuint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLuint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1609,8 +1702,13 @@
         (GLenum)pname,
         (GLuint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -1662,11 +1760,20 @@
 static void
 android_glSamplerParameterIiv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject param_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *param = (GLint *) 0;
 
+    if (!param_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "param == null";
+        goto exit;
+    }
     param = (GLint *)getPointer(_env, param_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (param == NULL) {
         char * _paramBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1677,9 +1784,14 @@
         (GLenum)pname,
         (GLint *)param
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)param, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glSamplerParameterIuiv ( GLuint sampler, GLenum pname, const GLuint *param ) */
@@ -1730,11 +1842,20 @@
 static void
 android_glSamplerParameterIuiv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject param_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *param = (GLuint *) 0;
 
+    if (!param_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "param == null";
+        goto exit;
+    }
     param = (GLuint *)getPointer(_env, param_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (param == NULL) {
         char * _paramBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1745,9 +1866,14 @@
         (GLenum)pname,
         (GLuint *)param
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)param, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glGetSamplerParameterIiv ( GLuint sampler, GLenum pname, GLint *params ) */
@@ -1798,11 +1924,20 @@
 static void
 android_glGetSamplerParameterIiv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1813,8 +1948,13 @@
         (GLenum)pname,
         (GLint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -1866,11 +2006,20 @@
 static void
 android_glGetSamplerParameterIuiv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLuint *params = (GLuint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLuint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -1881,8 +2030,13 @@
         (GLenum)pname,
         (GLuint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index 10090a1..740b24d 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>
@@ -240,10 +242,17 @@
 
     sp<hardware::IBinder> binder = JHwBinder::GetNativeContext(env, thiz);
 
+    sp<hidl::base::V1_0::IBase> base = hidl::base::V1_0::IHwBase::asInterface(binder);
+    if (base.get() == nullptr) {
+        LOG(ERROR) << "IBinder object cannot be casted to the base interface.";
+        signalExceptionForError(env, UNKNOWN_ERROR);
+        return;
+    }
+
     bool ok = hardware::defaultServiceManager()->add(
                 interfaceChain,
                 serviceName,
-                binder);
+                base);
 
     env->ReleaseStringUTFChars(serviceNameObj, serviceName);
     serviceName = NULL;
@@ -289,8 +298,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/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp
index ad7d744..bf0e9ed 100644
--- a/core/jni/com_google_android_gles_jni_GLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp
@@ -420,6 +420,9 @@
 static void
 android_glColorPointerBounds__IIILjava_nio_Buffer_2I
   (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jobject pointer_buf, jint remaining) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
@@ -438,17 +441,29 @@
         (GLvoid *)pointer,
         (GLsizei)remaining
     );
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glCompressedTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data ) */
 static void
 android_glCompressedTexImage2D__IIIIIIILjava_nio_Buffer_2
   (JNIEnv *_env, jobject _this, jint target, jint level, jint internalformat, jint width, jint height, jint border, jint imageSize, jobject data_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLvoid *data = (GLvoid *) 0;
 
+    if (!data_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "data == null";
+        goto exit;
+    }
     data = (GLvoid *)getPointer(_env, data_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (data == NULL) {
         char * _dataBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
@@ -464,20 +479,34 @@
         (GLsizei)imageSize,
         (GLvoid *)data
     );
+
+exit:
     if (_array) {
         releasePointer(_env, _array, data, JNI_FALSE);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glCompressedTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data ) */
 static void
 android_glCompressedTexSubImage2D__IIIIIIIILjava_nio_Buffer_2
   (JNIEnv *_env, jobject _this, jint target, jint level, jint xoffset, jint yoffset, jint width, jint height, jint format, jint imageSize, jobject data_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLvoid *data = (GLvoid *) 0;
 
+    if (!data_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "data == null";
+        goto exit;
+    }
     data = (GLvoid *)getPointer(_env, data_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (data == NULL) {
         char * _dataBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
@@ -494,9 +523,14 @@
         (GLsizei)imageSize,
         (GLvoid *)data
     );
+
+exit:
     if (_array) {
         releasePointer(_env, _array, data, JNI_FALSE);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glCopyTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border ) */
@@ -601,6 +635,12 @@
     jint _remaining;
     GLuint *textures = (GLuint *) 0;
 
+    if (!textures_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "textures == null";
+        goto exit;
+    }
     textures = (GLuint *)getPointer(_env, textures_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -705,6 +745,12 @@
     jint _remaining;
     GLvoid *indices = (GLvoid *) 0;
 
+    if (!indices_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "indices == null";
+        goto exit;
+    }
     indices = (GLvoid *)getPointer(_env, indices_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < count) {
         _exception = 1;
@@ -860,6 +906,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -1006,6 +1058,12 @@
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -1154,6 +1212,12 @@
     jint _remaining;
     GLuint *textures = (GLuint *) 0;
 
+    if (!textures_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "textures == null";
+        goto exit;
+    }
     textures = (GLuint *)getPointer(_env, textures_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -1580,6 +1644,12 @@
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -2038,6 +2108,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -2166,6 +2242,12 @@
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -2322,6 +2404,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -2505,6 +2593,12 @@
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -2644,11 +2738,20 @@
 static void
 android_glLoadMatrixf__Ljava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jobject m_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *m = (GLfloat *) 0;
 
+    if (!m_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "m == null";
+        goto exit;
+    }
     m = (GLfloat *)getPointer(_env, m_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (m == NULL) {
         char * _mBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -2657,9 +2760,14 @@
     glLoadMatrixf(
         (GLfloat *)m
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)m, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glLoadMatrixx ( const GLfixed *m ) */
@@ -2708,11 +2816,20 @@
 static void
 android_glLoadMatrixx__Ljava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jobject m_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *m = (GLfixed *) 0;
 
+    if (!m_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "m == null";
+        goto exit;
+    }
     m = (GLfixed *)getPointer(_env, m_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (m == NULL) {
         char * _mBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -2721,9 +2838,14 @@
     glLoadMatrixx(
         (GLfixed *)m
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)m, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glLogicOp ( GLenum opcode ) */
@@ -2836,6 +2958,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -2991,6 +3119,12 @@
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -3100,11 +3234,20 @@
 static void
 android_glMultMatrixf__Ljava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jobject m_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *m = (GLfloat *) 0;
 
+    if (!m_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "m == null";
+        goto exit;
+    }
     m = (GLfloat *)getPointer(_env, m_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (m == NULL) {
         char * _mBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -3113,9 +3256,14 @@
     glMultMatrixf(
         (GLfloat *)m
     );
+
+exit:
     if (_array) {
         _env->ReleaseFloatArrayElements(_array, (jfloat*)m, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glMultMatrixx ( const GLfixed *m ) */
@@ -3164,11 +3312,20 @@
 static void
 android_glMultMatrixx__Ljava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jobject m_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *m = (GLfixed *) 0;
 
+    if (!m_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "m == null";
+        goto exit;
+    }
     m = (GLfixed *)getPointer(_env, m_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (m == NULL) {
         char * _mBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -3177,9 +3334,14 @@
     glMultMatrixx(
         (GLfixed *)m
     );
+
+exit:
     if (_array) {
         _env->ReleaseIntArrayElements(_array, (jint*)m, JNI_ABORT);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glMultiTexCoord4f ( GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q ) */
@@ -3234,6 +3396,9 @@
 static void
 android_glNormalPointerBounds__IILjava_nio_Buffer_2I
   (JNIEnv *_env, jobject _this, jint type, jint stride, jobject pointer_buf, jint remaining) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
@@ -3251,6 +3416,9 @@
         (GLvoid *)pointer,
         (GLsizei)remaining
     );
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glOrthof ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) */
@@ -3347,11 +3515,20 @@
 static void
 android_glReadPixels__IIIIIILjava_nio_Buffer_2
   (JNIEnv *_env, jobject _this, jint x, jint y, jint width, jint height, jint format, jint type, jobject pixels_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLvoid *pixels = (GLvoid *) 0;
 
+    if (!pixels_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "pixels == null";
+        goto exit;
+    }
     pixels = (GLvoid *)getPointer(_env, pixels_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (pixels == NULL) {
         char * _pixelsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
@@ -3366,8 +3543,13 @@
         (GLenum)type,
         (GLvoid *)pixels
     );
+
+exit:
     if (_array) {
-        releasePointer(_env, _array, pixels, JNI_TRUE);
+        releasePointer(_env, _array, pixels, _exception ? JNI_FALSE : JNI_TRUE);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -3493,6 +3675,9 @@
 static void
 android_glTexCoordPointerBounds__IIILjava_nio_Buffer_2I
   (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jobject pointer_buf, jint remaining) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
@@ -3511,6 +3696,9 @@
         (GLvoid *)pointer,
         (GLsizei)remaining
     );
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glTexEnvf ( GLenum target, GLenum pname, GLfloat param ) */
@@ -3608,6 +3796,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -3751,6 +3945,12 @@
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -3803,6 +4003,9 @@
 static void
 android_glTexImage2D__IIIIIIIILjava_nio_Buffer_2
   (JNIEnv *_env, jobject _this, jint target, jint level, jint internalformat, jint width, jint height, jint border, jint format, jint type, jobject pixels_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
@@ -3829,6 +4032,9 @@
     if (_array) {
         releasePointer(_env, _array, pixels, JNI_FALSE);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glTexParameterf ( GLenum target, GLenum pname, GLfloat param ) */
@@ -3857,6 +4063,9 @@
 static void
 android_glTexSubImage2D__IIIIIIIILjava_nio_Buffer_2
   (JNIEnv *_env, jobject _this, jint target, jint level, jint xoffset, jint yoffset, jint width, jint height, jint format, jint type, jobject pixels_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
@@ -3883,6 +4092,9 @@
     if (_array) {
         releasePointer(_env, _array, pixels, JNI_FALSE);
     }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glTranslatef ( GLfloat x, GLfloat y, GLfloat z ) */
@@ -3911,6 +4123,9 @@
 static void
 android_glVertexPointerBounds__IIILjava_nio_Buffer_2I
   (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jobject pointer_buf, jint remaining) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
@@ -3929,6 +4144,9 @@
         (GLvoid *)pointer,
         (GLsizei)remaining
     );
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glViewport ( GLint x, GLint y, GLsizei width, GLsizei height ) */
@@ -4041,6 +4259,12 @@
     jint _exponentRemaining;
     GLint *exponent = (GLint *) 0;
 
+    if (!mantissa_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "mantissa == null";
+        goto exit;
+    }
     mantissa = (GLfixed *)getPointer(_env, mantissa_buf, (jarray*)&_mantissaArray, &_mantissaRemaining, &_mantissaBufferOffset);
     if (_mantissaRemaining < 16) {
         _exception = 1;
@@ -4048,6 +4272,12 @@
         _exceptionMessage = "remaining() < 16 < needed";
         goto exit;
     }
+    if (!exponent_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "exponent == null";
+        goto exit;
+    }
     exponent = (GLint *)getPointer(_env, exponent_buf, (jarray*)&_exponentArray, &_exponentRemaining, &_exponentBufferOffset);
     if (_exponentRemaining < 16) {
         _exception = 1;
@@ -4144,6 +4374,12 @@
     jint _remaining;
     GLvoid *data = (GLvoid *) 0;
 
+    if (!data_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "data == null";
+        goto exit;
+    }
     data = (GLvoid *)getPointer(_env, data_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < size) {
         _exception = 1;
@@ -4232,6 +4468,12 @@
     jint _remaining;
     GLfloat *equation = (GLfloat *) 0;
 
+    if (!equation_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "equation == null";
+        goto exit;
+    }
     equation = (GLfloat *)getPointer(_env, equation_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 4) {
         _exception = 1;
@@ -4318,6 +4560,12 @@
     jint _remaining;
     GLfixed *equation = (GLfixed *) 0;
 
+    if (!equation_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "equation == null";
+        goto exit;
+    }
     equation = (GLfixed *)getPointer(_env, equation_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 4) {
         _exception = 1;
@@ -4428,6 +4676,12 @@
     jint _remaining;
     GLuint *buffers = (GLuint *) 0;
 
+    if (!buffers_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "buffers == null";
+        goto exit;
+    }
     buffers = (GLuint *)getPointer(_env, buffers_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -4532,6 +4786,12 @@
     jint _remaining;
     GLuint *buffers = (GLuint *) 0;
 
+    if (!buffers_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "buffers == null";
+        goto exit;
+    }
     buffers = (GLuint *)getPointer(_env, buffers_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -4604,11 +4864,20 @@
 static void
 android_glGetBooleanv__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLboolean *params = (GLboolean *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLboolean *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -4618,8 +4887,13 @@
         (GLenum)pname,
         (GLboolean *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -4686,11 +4960,20 @@
 static void
 android_glGetClipPlanef__ILjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint pname, jobject eqn_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *eqn = (GLfloat *) 0;
 
+    if (!eqn_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "eqn == null";
+        goto exit;
+    }
     eqn = (GLfloat *)getPointer(_env, eqn_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (eqn == NULL) {
         char * _eqnBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -4700,8 +4983,13 @@
         (GLenum)pname,
         (GLfloat *)eqn
     );
+
+exit:
     if (_array) {
-        _env->ReleaseFloatArrayElements(_array, (jfloat*)eqn, 0);
+        _env->ReleaseFloatArrayElements(_array, (jfloat*)eqn, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -4752,11 +5040,20 @@
 static void
 android_glGetClipPlanex__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint pname, jobject eqn_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *eqn = (GLfixed *) 0;
 
+    if (!eqn_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "eqn == null";
+        goto exit;
+    }
     eqn = (GLfixed *)getPointer(_env, eqn_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (eqn == NULL) {
         char * _eqnBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -4766,8 +5063,13 @@
         (GLenum)pname,
         (GLfixed *)eqn
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)eqn, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)eqn, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -4818,11 +5120,20 @@
 static void
 android_glGetFixedv__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -4832,8 +5143,13 @@
         (GLenum)pname,
         (GLfixed *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -4884,11 +5200,20 @@
 static void
 android_glGetFloatv__ILjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -4898,8 +5223,13 @@
         (GLenum)pname,
         (GLfloat *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseFloatArrayElements(_array, (jfloat*)params, 0);
+        _env->ReleaseFloatArrayElements(_array, (jfloat*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -5007,6 +5337,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -5179,6 +5515,12 @@
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -5337,6 +5679,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -5481,6 +5829,12 @@
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -5619,6 +5973,12 @@
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -5751,6 +6111,12 @@
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -5861,6 +6227,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -5949,6 +6321,12 @@
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -6037,6 +6415,12 @@
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -6178,6 +6562,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -6274,6 +6664,12 @@
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -6303,6 +6699,9 @@
 static void
 android_glPointSizePointerOESBounds__IILjava_nio_Buffer_2I
   (JNIEnv *_env, jobject _this, jint type, jint stride, jobject pointer_buf, jint remaining) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
@@ -6320,6 +6719,9 @@
         (GLvoid *)pointer,
         (GLsizei)remaining
     );
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glTexCoordPointer ( GLint size, GLenum type, GLsizei stride, GLint offset ) */
@@ -6429,6 +6831,12 @@
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     int _needed;
     switch (pname) {
@@ -6539,6 +6947,12 @@
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -6638,6 +7052,12 @@
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -6726,6 +7146,12 @@
     jint _remaining;
     GLfixed *params = (GLfixed *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfixed *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 1) {
         _exception = 1;
@@ -6846,6 +7272,12 @@
     jint _remaining;
     GLfloat *coords = (GLfloat *) 0;
 
+    if (!coords_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "coords == null";
+        goto exit;
+    }
     coords = (GLfloat *)getPointer(_env, coords_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 5) {
         _exception = 1;
@@ -6943,6 +7375,12 @@
     jint _remaining;
     GLint *coords = (GLint *) 0;
 
+    if (!coords_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "coords == null";
+        goto exit;
+    }
     coords = (GLint *)getPointer(_env, coords_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 5) {
         _exception = 1;
@@ -7040,6 +7478,12 @@
     jint _remaining;
     GLshort *coords = (GLshort *) 0;
 
+    if (!coords_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "coords == null";
+        goto exit;
+    }
     coords = (GLshort *)getPointer(_env, coords_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 5) {
         _exception = 1;
@@ -7137,6 +7581,12 @@
     jint _remaining;
     GLfixed *coords = (GLfixed *) 0;
 
+    if (!coords_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "coords == null";
+        goto exit;
+    }
     coords = (GLfixed *)getPointer(_env, coords_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < 5) {
         _exception = 1;
@@ -7172,6 +7622,9 @@
 static void
 android_glMatrixIndexPointerOESBounds__IIILjava_nio_Buffer_2I
   (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jobject pointer_buf, jint remaining) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
@@ -7190,6 +7643,9 @@
         (GLvoid *)pointer,
         (GLsizei)remaining
     );
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glMatrixIndexPointerOES ( GLint size, GLenum type, GLsizei stride, GLint offset ) */
@@ -7208,6 +7664,9 @@
 static void
 android_glWeightPointerOESBounds__IIILjava_nio_Buffer_2I
   (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jobject pointer_buf, jint remaining) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jarray _array = (jarray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
@@ -7226,6 +7685,9 @@
         (GLvoid *)pointer,
         (GLsizei)remaining
     );
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
 }
 
 /* void glWeightPointerOES ( GLint size, GLenum type, GLsizei stride, GLint offset ) */
@@ -7403,6 +7865,12 @@
     jint _remaining;
     GLuint *framebuffers = (GLuint *) 0;
 
+    if (!framebuffers_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "framebuffers == null";
+        goto exit;
+    }
     framebuffers = (GLuint *)getPointer(_env, framebuffers_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -7499,6 +7967,12 @@
     jint _remaining;
     GLuint *renderbuffers = (GLuint *) 0;
 
+    if (!renderbuffers_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "renderbuffers == null";
+        goto exit;
+    }
     renderbuffers = (GLuint *)getPointer(_env, renderbuffers_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -7644,6 +8118,12 @@
     jint _remaining;
     GLuint *framebuffers = (GLuint *) 0;
 
+    if (!framebuffers_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "framebuffers == null";
+        goto exit;
+    }
     framebuffers = (GLuint *)getPointer(_env, framebuffers_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -7740,6 +8220,12 @@
     jint _remaining;
     GLuint *renderbuffers = (GLuint *) 0;
 
+    if (!renderbuffers_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "renderbuffers == null";
+        goto exit;
+    }
     renderbuffers = (GLuint *)getPointer(_env, renderbuffers_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (_remaining < n) {
         _exception = 1;
@@ -7824,11 +8310,20 @@
             "glGetFramebufferAttachmentParameterivOES");
             return;
     }
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -7840,8 +8335,13 @@
         (GLint)pname,
         (GLint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -7903,11 +8403,20 @@
             "glGetRenderbufferParameterivOES");
             return;
     }
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -7918,8 +8427,13 @@
         (GLint)pname,
         (GLint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -7981,11 +8495,20 @@
             "glGetTexGenfv");
             return;
     }
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -7996,8 +8519,13 @@
         (GLint)pname,
         (GLfloat *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseFloatArrayElements(_array, (jfloat*)params, 0);
+        _env->ReleaseFloatArrayElements(_array, (jfloat*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -8059,11 +8587,20 @@
             "glGetTexGeniv");
             return;
     }
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -8074,8 +8611,13 @@
         (GLint)pname,
         (GLint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -8137,11 +8679,20 @@
             "glGetTexGenxv");
             return;
     }
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -8152,8 +8703,13 @@
         (GLint)pname,
         (GLint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -8280,11 +8836,20 @@
             "glTexGenfv");
             return;
     }
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jfloatArray _array = (jfloatArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLfloat *params = (GLfloat *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
@@ -8295,8 +8860,13 @@
         (GLint)pname,
         (GLfloat *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseFloatArrayElements(_array, (jfloat*)params, 0);
+        _env->ReleaseFloatArrayElements(_array, (jfloat*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -8374,11 +8944,20 @@
             "glTexGeniv");
             return;
     }
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -8389,8 +8968,13 @@
         (GLint)pname,
         (GLint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
@@ -8468,11 +9052,20 @@
             "glTexGenxv");
             return;
     }
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
     jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLint *params = (GLint *) 0;
 
+    if (!params_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
     params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (params == NULL) {
         char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
@@ -8483,8 +9076,13 @@
         (GLint)pname,
         (GLint *)params
     );
+
+exit:
     if (_array) {
-        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
 
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_out_micro.xml b/core/res/res/anim/slide_out_micro.xml
index c647093..01df0da 100644
--- a/core/res/res/anim/slide_out_micro.xml
+++ b/core/res/res/anim/slide_out_micro.xml
@@ -19,7 +19,7 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-     android:zAdjustment="top">
+     android:zAdjustment="normal">
     <translate android:fromYDelta="0" android:toYDelta="5%p"
                android:duration="250"
                android:interpolator="@android:interpolator/fast_out_slow_in"/>
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 e43f1ba..95cb0d8 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Laat die program toe om die kitsboodskapdiens te gebruik om oproepe sonder jou ingryping te maak."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"lees foonstatus en identiteit"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Laat die program toe om toegang tot die foonfunksies van die toestel te verkry. Hierdie toestemming laat die program toe om te bepaal wat die foonnommer en toestel-IDs is, of die oproep aan die gang is, en die afgeleë nommer wat deur \'n oproep verbind word."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"lees foonnommer"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Gee die program toegang tot die toestel se foonnommer."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"verhoed dat tablet slaap"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"keer TV om te sluimer"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"verhoed foon om te slaap"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2e werk-<xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3e werk-<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Jy sal enige veranderinge verloor en die demonstrasie sal oor <xliff:g id="TIMEOUT">%1$s</xliff:g> sekondes weer begin …"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Kanselleer"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Stel nou terug"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Doen \'n fabriekterugstelling om hierdie toestel sonder beperkinge te gebruik"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Raak om meer te wete te kom."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index af8c592..501179d 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"መተግበሪያው ያለእርስዎ ጣልቃ ገብነት ጥሪዎችን ለማድረግ የአይኤምኤስ አገልግሎቱን እንዲጠቀም ያስችለዋል።"</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"የስልክ ሁኔታና ማንነት አንብብ"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"መተግበሪያው የመሳሪያውን የስልክ ባህሪያት ላይ እንዲደርስ ይፈቅድለታል። ይህ ፈቃድ መተግበሪያው የስልክ ቁጥሩን እና የመሳሪያውን መታወቂያዎች፣ ጥሪ የነቃ እንደሆነ፣ እና በጥሪ የተገናኘውን የሩቅ ቁጥር እንዲወስን ይፈቅድለታል።"</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ስልክ ቁጥር አንብብ"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"መተግበሪያው የመሣሪያውን ስልክ ቁጥር እንዲደርስበት ይፈቅድለታል።"</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ጡባዊ ከማንቀላፋት ተከላከል"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"ቴሌቪዥን እንዳይተኛ አግድ"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ስልክ ከማንቀላፋት ተከላከል"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2ኛ ስራ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3ኛ ስራ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"ማንኛቸውም ለውጦች ይጠፋሉ፣ እና ማሳያው በ<xliff:g id="TIMEOUT">%1$s</xliff:g> ሰከንዶች ውስጥ እንደገና ይጀምራል…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"ይቅር"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"አሁን ዳግም አስጀምር"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"ይህን መሣሪያ ያለምንም ገደብ ለመጠቀም የፋብሪካ ዳግም ያስጀምሩ"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"የበለጠ ለመረዳት ይንኩ።"</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index b3c24e5..f406297 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -389,6 +389,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"للسماح للتطبيق باستخدام خدمة الرسائل الفورية لإجراء المكالمات دون تدخل منك."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"قراءة حالة الهاتف والهوية"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"للسماح للتطبيق بالدخول إلى ميزات الهاتف في الجهاز. ويتيح هذا الإذن للتطبيق تحديد رقم الهاتف ومعرّفات الجهاز، وما إذا كانت هناك مكالمة نشطة والرقم البعيد الذي تم الاتصال به في المكالمة."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"قراءة رقم الهاتف"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"للسماح للتطبيق بالوصول إلى رقم الهاتف على الجهاز."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"منع الجهاز اللوحي من الدخول في وضع السكون"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"منع التلفزيون من الدخول في وضع السكون"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"منع الهاتف من الدخول في وضع السكون"</string>
@@ -1151,16 +1153,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 +1670,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"العمل الثاني <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"العمل الثالث <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1825,8 +1825,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"ستفقد أي تغييرات وسيبدأ العرض التوضيحي مرة أخرى خلال <xliff:g id="TIMEOUT">%1$s</xliff:g> من الثواني…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"إلغاء"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"إعادة التعيين الآن"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"يمكنك إعادة تعيين بيانات المصنع لاستخدام هذا الجهاز بدون قيود"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"المس للتعرف على مزيد من المعلومات."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 7e9c508..0f41311 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Tətbiqə müdaxilə olmadan zəng etmək üçün IMS xidmətindən istifadə etməyə imkan verir."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"telefon statusunu və identifikasiyanı oxuyur"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Tətbiqə cihazın telefon funksiyalarına giriş icazəsi verir. Belə icazəli tətbiq bu telefonun nömrəsini və cihaz İD\'ni, zəngin aktiv olub-olmadığını və zəng edilən nömrəni müəyyən edə bilər."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"telefon nömrəsini oxuyun"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Tətbiqə cihazın telefon nömrəsinə daxil olmağa icazə verir."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"planşetin yuxu rejiminin qarşısını almaq"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"TV-ni yuxu rejiminə keçməyə qoyma"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"telefonun yuxu rejiminə keçməsini əngəllə"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2-ci İş <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3-cü İş <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Hər hansı dəyişikliyi itirəcəksiniz və demo <xliff:g id="TIMEOUT">%1$s</xliff:g> saniyəyə yenidən başlayacaq…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Ləğv edin"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"İndi sıfırlayın"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Bu cihazı məhdudiyyətsiz istifadə etmək üçün zavod sıfırlaması edin"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Daha çox məlumat üçün toxunun."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 6caf561..7cbeb1a 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -380,6 +380,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Dozvoljava aplikaciji da koristi uslugu razmene trenutnih poruka da bi upućivala pozive bez vaše intervencije."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"čitanje statusa i identiteta telefona"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Dozvoljava aplikaciji da pristupa funkcijama telefona na uređaju. Ova dozvola omogućava aplikaciji da utvrdi broj telefona i ID-ove uređaja, zatim da li je poziv aktivan, kao i broj daljinskog uređaja sa kojim je uspostavljen poziv."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"čitanje broja telefona"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Dozvoljava aplikaciji da pristupa broju telefona na uređaju."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"sprečavanje prelaska tableta u stanje spavanja"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"sprečavanje TV-a da pređe u stanje spavanja"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"sprečavanje prelaska telefona u stanje spavanja"</string>
@@ -1082,16 +1084,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 +1589,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. poslovni <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. poslovni imejl <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1717,8 +1717,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Izgubićete sve promene i demonstracija će ponovo početi za <xliff:g id="TIMEOUT">%1$s</xliff:g> sek…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Otkaži"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Resetuj"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Resetujte uređaj na fabrička podešavanja da biste ga koristili bez ograničenja"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Dodirnite da biste saznali više."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-be-rBY/strings.xml b/core/res/res/values-be-rBY/strings.xml
index c076db2..2299125 100644
--- a/core/res/res/values-be-rBY/strings.xml
+++ b/core/res/res/values-be-rBY/strings.xml
@@ -383,6 +383,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Дазваляе праграмам выкарыстоўваць службу IMS, каб рабіць выклікі без вашага ўмяшання."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"чытанне статусу тэлефона і ідэнтыфікацыя"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Дазваляе прыкладанням атрымлiваць доступ да функцый тэлефона на прыладзе. Дзякуючы гэтаму дазволу прыкладанне можа вызначаць iдэнтыфiкатары нумару тэлефона i прылады, незалежна ад таго, цi актыўны выклiк, i аддалены нумар, на якi робiцца выклiк."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"чытаць нумар тэлефона"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Праграма зможа атрымліваць доступ да нумара тэлефона прылады."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"прадухіліць планшэт ад пераходу ў рэжым сну"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"прадухіленне пераходу тэлевізара ў рэжым сну"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"забараняць тэлефону пераходзіць ў рэжым сну"</string>
@@ -1105,16 +1107,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 +1616,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Другая праца <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Трэцяя праца <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1753,8 +1753,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Усе змены будуць страчаны, і дэманстрацыя пачнецца зноў праз <xliff:g id="TIMEOUT">%1$s</xliff:g> с…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Скасаваць"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Выканаць скід"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Выканайце скід да заводскіх налад, каб выкарыстоўваць гэту прыладу без абмежаванняў"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Краніце, каб даведацца больш."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 2d6bdb2..aac482c 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Разрешава на приложението да използва услугата за незабавни съобщения за извършване на обаждания без намеса от ваша страна."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"четене на състоянието и идентификационните данни на телефона"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Разрешава на приложението достъп до телефонните функции на устройството. Това разрешение позволява на приложението да определя телефонния номер и идентификационния номер на устройството, дали се води разговор и отдалечения номер, до който е установена връзка с обаждането."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"четене на телефонния номер"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Разрешава на приложението да осъществява достъп до телефонния номер на устройството."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"предотвратяване на спящия режим на таблета"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"предотвратяване на преминаването на телевизора в спящ режим"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"предотвратява спящ режим на телефона"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Втори служебен профил (<xliff:g id="LABEL">%1$s</xliff:g>)"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Трети служебен профил (<xliff:g id="LABEL">%1$s</xliff:g>)"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Ще загубите всички промени и демонстрацията ще започне отново след <xliff:g id="TIMEOUT">%1$s</xliff:g> секунди…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Отказ"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Нулиране сега"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Възстановете фабричните настройки на това устройство, за да го използвате без ограничения"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Докоснете, за да научите повече."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index 21b737a..99a131b 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"আপনার হস্তক্ষেপ ছাড়াই কল করতে অ্যাপ্লিকেশানটিকে IMS পরিষেবা ব্যবহারের অনুমতি দিন৷"</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"ফোনের স্থিতি এবং পরিচয় পড়ুন"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"অ্যাপ্লিকেশানটিকে ডিভাইসের ফোন বৈশিষ্ট্যগুলিকে অ্যাক্সেস করার অনুমতি দেয়৷ এই অনুমতিটি অ্যাপ্লিকেশানটিকে একটি কল সক্রিয় থাকা অবস্থায় এবং দূরবর্তী নম্বর একটি কল দ্বারা সংযুক্ত থাকাকালীনও ফোন নম্বর এবং ডিভাইসের IDগুলি নির্ধারণ করার অনুমতি দেয়৷"</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"অ্যাপটিকে ফোন নম্বর পড়ার অনুমতি দিন"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"অ্যাপটিকে এই ডিভাইসের ফোন নম্বর অ্যাক্সেস করার মঞ্জুরি দেয়"</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ঘুমানো থেকে ট্যাবলেটকে প্রতিরোধ করে"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"টিভিকে নিদ্রায় যাওয়া থেকে প্রতিরোধ করে"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ঘুমানো থেকে ফোনটিকে প্রতিরোধ করে"</string>
@@ -605,7 +607,7 @@
     <string name="phoneTypeRadio" msgid="4093738079908667513">"রেডিও"</string>
     <string name="phoneTypeTelex" msgid="3367879952476250512">"টেলেক্স"</string>
     <string name="phoneTypeTtyTdd" msgid="8606514378585000044">"TTY TDD"</string>
-    <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"কার্যক্ষেত্রের মোবাইল"</string>
+    <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"অফিসের মোবাইল"</string>
     <string name="phoneTypeWorkPager" msgid="649938731231157056">"কার্যক্ষেত্রের পেজার"</string>
     <string name="phoneTypeAssistant" msgid="5596772636128562884">"সহায়ক"</string>
     <string name="phoneTypeMms" msgid="7254492275502768992">"MMS"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"দ্বিতীয় কার্যক্ষেত্রের <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"তৃতীয় কার্যক্ষেত্রের <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"আপনার করা যে কোনো পরিবর্তন মুছে যাবে এবং <xliff:g id="TIMEOUT">%1$s</xliff:g> সেকেন্ডের মধ্যে ডেমো আবার শুরু হবে…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"বাতিল করুন"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"এখনই পুনরায় সেট করুন"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"কোনো বিধিনিষেধ ছাড়াই এই ডিভাইসটিকে ব্যবহার করতে ফ্যাক্টরি রিসেট করুন"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"আরো জানতে স্পর্শ করুন৷"</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bs-rBA/strings.xml b/core/res/res/values-bs-rBA/strings.xml
index 80ee407..0cdd4b7 100644
--- a/core/res/res/values-bs-rBA/strings.xml
+++ b/core/res/res/values-bs-rBA/strings.xml
@@ -380,6 +380,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Omogućava aplikaciji da koristi IMS uslugu za pozivanje bez vaše intervencije."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"čitanje statusa i identiteta telefona"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Omogućava aplikaciji pristup telefonskim funkcijama uređaja. Ova dozvola omogućava aplikaciji određivanje telefonskog i identifikacionog broja uređaja, bez obzira da li je poziv aktivan i da li je uspostavljena veza sa pozivanim brojem."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"čitanje telefonskog broja"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Dopušta aplikaciji pristup telefonskom broju telefona."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"sprečavanje tableta da uđe u režim mirovanja"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"spriječi ulazak TV-a u režim mirovanja"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"sprečavanje telefona da uđe u režim mirovanja"</string>
@@ -551,35 +553,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 +602,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 +618,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>
@@ -646,17 +648,17 @@
     <string name="relationTypeAssistant" msgid="6274334825195379076">"Pomoćnik"</string>
     <string name="relationTypeBrother" msgid="8757913506784067713">"Brat"</string>
     <string name="relationTypeChild" msgid="1890746277276881626">"Dijete"</string>
-    <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"Domaći partner"</string>
+    <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"Nevjenčani partner"</string>
     <string name="relationTypeFather" msgid="5228034687082050725">"Otac"</string>
     <string name="relationTypeFriend" msgid="7313106762483391262">"Prijatelj"</string>
-    <string name="relationTypeManager" msgid="6365677861610137895">"Menadžer"</string>
+    <string name="relationTypeManager" msgid="6365677861610137895">"Šef"</string>
     <string name="relationTypeMother" msgid="4578571352962758304">"Majka"</string>
     <string name="relationTypeParent" msgid="4755635567562925226">"Roditelj"</string>
     <string name="relationTypePartner" msgid="7266490285120262781">"Partner"</string>
     <string name="relationTypeReferredBy" msgid="101573059844135524">"Uputio(la)"</string>
-    <string name="relationTypeRelative" msgid="1799819930085610271">"Rođak"</string>
+    <string name="relationTypeRelative" msgid="1799819930085610271">"Rođak/ica"</string>
     <string name="relationTypeSister" msgid="1735983554479076481">"Sestra"</string>
-    <string name="relationTypeSpouse" msgid="394136939428698117">"Bračni partner"</string>
+    <string name="relationTypeSpouse" msgid="394136939428698117">"Suprug/a"</string>
     <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Prilagođeno"</string>
     <string name="sipAddressTypeHome" msgid="6093598181069359295">"Kuća"</string>
     <string name="sipAddressTypeWork" msgid="6920725730797099047">"Posao"</string>
@@ -1084,16 +1086,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 +1591,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. poslovni <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. poslovni <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1719,8 +1719,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Nestat će sve izmjene, a demonstracija će početi ponovo za <xliff:g id="TIMEOUT">%1$s</xliff:g> sek…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Otkaži"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Vrati sada na početne postavke"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Vratite uređaj na fabričke postavke kako biste ga koristili bez ograničenja"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Dodirnite da saznate više."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 35b2918..339dec4 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permet que l\'aplicació utilitzi el servei IMS per fer trucades sense la teva intervenció."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"veure l\'estat i la identitat del telèfon"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permet que l\'aplicació accedeixi a les funcions de telèfon del dispositiu. Aquest permís permet que l\'aplicació determini el número de telèfon i els identificadors del dispositiu, si hi ha una trucada activa i el número remot connectat amb una trucada."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"llegeix el número de telèfon"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Permet que l\'aplicació accedeixi al número de telèfon del dispositiu."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"evita que la tauleta entri en mode de repòs"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"impedir que el televisor entri en mode de repòs"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir que el telèfon entri en mode de repòs"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2n <xliff:g id="LABEL">%1$s</xliff:g> de la feina"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3r <xliff:g id="LABEL">%1$s</xliff:g> de la feina"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Perdràs els canvis, i la demostració tornarà a començar d\'aquí a <xliff:g id="TIMEOUT">%1$s</xliff:g> segons…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Cancel·la"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Restableix ara"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Restableix les dades de fàbrica del dispositiu per utilitzar-lo sense restriccions"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toca per obtenir més informació."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 95a6728..4f36487 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -383,6 +383,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Umožňuje aplikaci používat službu zasílání rychlých zpráv k uskutečňování hovorů bez vašeho zásahu."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"čtení stavu a identity telefonu"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Umožňuje aplikaci získat přístup k telefonním funkcím zařízení. Toto oprávnění umožňuje aplikaci zjistit telefonní číslo telefonu, identifikační čísla zařízení, zda zrovna probíhá hovor, a vzdálené číslo, ke kterému je hovor připojen."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"přístup k telefonnímu číslu"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Umožňuje aplikaci zobrazit telefonní číslo zařízení."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"bránění přechodu tabletu do režimu spánku"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"zabránění přechodu televize do režimu spánku"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"bránění přechodu telefonu do režimu spánku"</string>
@@ -1105,16 +1107,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 +1616,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. <xliff:g id="LABEL">%1$s</xliff:g> do práce"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. <xliff:g id="LABEL">%1$s</xliff:g> do práce"</string>
     <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>
@@ -1753,8 +1753,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Ztratíte všechny provedené změny a ukázka se za <xliff:g id="TIMEOUT">%1$s</xliff:g> s spustí znovu…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Zrušit"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Resetovat"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Chcete-li toto zařízení používat bez omezení, obnovte jej do továrního nastavení"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Klepnutím zobrazíte další informace."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index a628e42..67e0ef0 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Tillader, at appen kan bruge chat-tjenesten til at foretage opkald, uden du gør noget."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"læse telefonens status og identitet"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Tillader, at appen kan få adgang til telefonfunktionerne på enheden. Med denne tilladelse kan appen fastslå telefonnummeret og enheds-id\'erne, hvorvidt et opkald er aktivt samt det eksterne nummer, der oprettes forbindelse til via et opkald."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"læs telefonnummer"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Tillader, at appen har adgang til enhedens telefonnummer."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"afholde tabletcomputeren fra at gå i dvale"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"forhindre tv i at gå i dvale"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"afholde telefonen fra at gå i dvale"</string>
@@ -1059,16 +1061,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Medielydstyrke"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Lydstyrke for meddelelser"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Standardringetone"</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">"Ringetoner"</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">"Alarmlyde"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Meddelelseslyde"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Ukendt"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">Tilgængelige Wi-Fi-netværk</item>
       <item quantity="other">Tilgængelige Wi-Fi-netværk</item>
@@ -1564,6 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. <xliff:g id="LABEL">%1$s</xliff:g> til arbejde"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. <xliff:g id="LABEL">%1$s</xliff:g> til arbejde"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Du mister alle ændringer, og demoen starter igen om <xliff:g id="TIMEOUT">%1$s</xliff:g> sekunder…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Annuller"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Nulstil nu"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Gendan fabriksdataene på enheden for at bruge den uden begrænsninger"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Tryk for at få flere oplysninger."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – deaktiveret"</string>
     <string name="conference_call" msgid="3751093130790472426">"Telefonmøde"</string>
+    <!-- no translation found for tooltip_popup_title (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 86f2070..28b9748 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Ermöglicht der App die Verwendung des IMS-Dienstes zum Tätigen von Anrufen ohne Nutzereingriffe"</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"Telefonstatus und Identität abrufen"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Ermöglicht der App, auf die Telefonfunktionen des Geräts zuzugreifen. Die Berechtigung erlaubt der App, die Telefonnummer und Geräte-IDs zu erfassen, festzustellen, ob gerade ein Gespräch geführt wird, und die Rufnummer verbundener Anrufer zu lesen."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"Telefonnummer lesen"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Der App den Zugriff auf die Telefonnummer des Geräts erlauben."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"Ruhezustand des Tablets deaktivieren"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"Ruhemodus des Fernsehers deaktivieren"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"Ruhezustand deaktivieren"</string>
@@ -1059,16 +1061,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Medienlautstärke"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Benachrichtigungslautstärke"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Standard-Klingelton"</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">"Ohne"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Klingeltöne"</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">"Weckertöne"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Benachrichtigungstöne"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Unbekannt"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">WLAN-Netzwerke verfügbar</item>
       <item quantity="one">WLAN-Netzwerk verfügbar</item>
@@ -1564,6 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. <xliff:g id="LABEL">%1$s</xliff:g> (geschäftlich)"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. <xliff:g id="LABEL">%1$s</xliff:g> (geschäftlich)"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Alle Änderungen gehen verloren und Demo wird in <xliff:g id="TIMEOUT">%1$s</xliff:g> Sekunden neu gestartet…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Abbrechen"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Jetzt zurücksetzen"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Gerät auf Werkseinstellungen zurücksetzen, um es ohne Einschränkungen zu nutzen"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Für weitere Informationen tippen."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> deaktiviert"</string>
     <string name="conference_call" msgid="3751093130790472426">"Telefonkonferenz"</string>
+    <!-- no translation found for tooltip_popup_title (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 4ce3a1f..5612a31 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Επιτρέπει στην εφαρμογή τη χρήση της υπηρεσίας IMS για την πραγματοποίηση κλήσεων χωρίς τη δική σας παρέμβαση."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"διαβάζει την κατάσταση και ταυτότητα τηλεφώνου"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Επιτρέπει στην εφαρμογή την πρόσβαση στις λειτουργίες τηλεφώνου της συσκευής. Αυτή η άδεια δίνει τη δυνατότητα στην εφαρμογή να καθορίζει τον αριθμό τηλεφώνου και τα αναγνωριστικά συσκευών, εάν μια κλήση είναι ενεργή, καθώς και τον απομακρυσμένο αριθμό που συνδέεται από μια κλήση."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ανάγνωση αριθμού τηλεφώνου"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Επιτρέπει στην εφαρμογή να έχει πρόσβαση στον αριθμό τηλεφώνου της συσκευής."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"αποτρέπει την μετάβαση του tablet σε κατάσταση αδράνειας"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"αποτρέπει την μετάβαση της τηλεόρασης σε κατάσταση αδράνειας"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"αποτρέπει το τηλεφώνο να μεταβεί σε κατάσταση αδράνειας"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> εργασίας 2"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> εργασίας 3"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Τυχόν αλλαγές που πραγματοποιήσατε θα χαθούν και η επίδειξη θα ξεκινήσει ξανά σε <xliff:g id="TIMEOUT">%1$s</xliff:g> δευτερόλεπτα…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Ακύρωση"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Επαναφορά τώρα"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Επαναφέρετε τις εργοστασιακές ρυθμίσεις για να χρησιμοποιήσετε αυτήν τη συσκευή χωρίς περιορισμούς"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Αγγίξτε για να μάθετε περισσότερα."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 72c1271..c267bc0 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Allows the app to use the IMS service to make calls without your intervention."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"read phone status and identity"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Allows the app to access the phone features of the device. This permission allows the app to determine the phone number and device IDs, whether a call is active and the remote number connected by a call."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"read phone number"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Allows the app to access the phone number of the device."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"prevent tablet from sleeping"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"prevent TV from sleeping"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"prevent phone from sleeping"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2nd Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3rd Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"You\'ll lose any changes and the demo will start again in <xliff:g id="TIMEOUT">%1$s</xliff:g> seconds…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Cancel"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Reset now"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Factory reset to use this device without restrictions"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Touch to find out more."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 72c1271..c267bc0 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Allows the app to use the IMS service to make calls without your intervention."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"read phone status and identity"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Allows the app to access the phone features of the device. This permission allows the app to determine the phone number and device IDs, whether a call is active and the remote number connected by a call."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"read phone number"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Allows the app to access the phone number of the device."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"prevent tablet from sleeping"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"prevent TV from sleeping"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"prevent phone from sleeping"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2nd Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3rd Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"You\'ll lose any changes and the demo will start again in <xliff:g id="TIMEOUT">%1$s</xliff:g> seconds…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Cancel"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Reset now"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Factory reset to use this device without restrictions"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Touch to find out more."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 72c1271..c267bc0 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Allows the app to use the IMS service to make calls without your intervention."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"read phone status and identity"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Allows the app to access the phone features of the device. This permission allows the app to determine the phone number and device IDs, whether a call is active and the remote number connected by a call."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"read phone number"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Allows the app to access the phone number of the device."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"prevent tablet from sleeping"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"prevent TV from sleeping"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"prevent phone from sleeping"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2nd Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3rd Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"You\'ll lose any changes and the demo will start again in <xliff:g id="TIMEOUT">%1$s</xliff:g> seconds…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Cancel"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Reset now"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Factory reset to use this device without restrictions"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Touch to find out more."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 738af8c..cbbdb0d 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permite que la aplicación utilice el servicio IMS para hacer llamadas sin tu intervención."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"leer la identidad y el estado del dispositivo"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite que la aplicación acceda a las funciones de teléfono del dispositivo. La aplicación puede utilizar este permiso para descubrir identificadores de dispositivos y números de teléfono, para saber si una llamada está activa y para conocer el número remoto con el que se ha establecido conexión mediante una llamada."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"leer el número de teléfono"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Permite que la app acceda al número de teléfono del dispositivo."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"evitar que el tablet entre en estado de inactividad"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"evitar que la TV entre en suspensión"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"evitar que el dispositivo entre en estado de inactividad"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo 2"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo 3"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Se perderán los cambios y la demostración volverá a iniciarse en <xliff:g id="TIMEOUT">%1$s</xliff:g> segundos…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Cancelar"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Restablecer ahora"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Restablece la configuración de fábrica para usar este dispositivo sin restricciones"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toca para obtener más información."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 3c2915d..c3751bd 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permite que la aplicación utilice el servicio IMS para realizar llamadas sin tu intervención."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"consultar la identidad y el estado del teléfono"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite que la aplicación acceda a las funciones de teléfono del dispositivo. La aplicación puede utilizar este permiso para descubrir identificadores de dispositivos y números de teléfono, para saber si una llamada está activa y para conocer el número remoto con el que se ha establecido conexión mediante una llamada."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"leer el número de teléfono"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Permite que la aplicación acceda al número de teléfono del dispositivo."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"impedir que el tablet entre en modo de suspensión"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"evitar que la TV entre en suspensión"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir que el teléfono entre en modo de suspensión"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo 2"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo 3"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Se perderán todos los cambios y la demostración volverá a empezar en <xliff:g id="TIMEOUT">%1$s</xliff:g> segundos…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Cancelar"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Restablecer ahora"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Restablece los datos de fábrica para usar este dispositivo sin restricciones"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toca para obtener más información."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 96b060f..648bd62 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Võimaldab rakendusel kasutada IMS-teenust kõnede tegemiseks ilma, et peaksite sekkuma."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"lugege telefoni olekut ja identiteeti"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Annab rakendusele juurdepääsu seadme telefonifunktsioonidele. See luba võimaldab rakendusel määrata telefoninumbri ja seadme ID-d ning kontrollida, kas kõne on aktiivne ja kaugnumber on kõne kaudu telefoniga ühendatud."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"lugeda telefoninumbrit"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Lubab rakendusel juurde pääseda seadme telefoninumbrile."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"tahvelarvuti uinumise vältimine"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"teleri unerežiimi lülitumise takistamine"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"väldi telefoni uinumist"</string>
@@ -650,7 +652,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>
@@ -1059,16 +1061,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Meediumi helitugevus"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Teatise helitugevus"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Vaikehelin"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Vaikimisi (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Puudub"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Helinad"</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">"Äratuse helid"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Märguannete helid"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Teadmata"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">WiFi-võrgud on saadaval</item>
       <item quantity="one">WiFi-võrk on saadaval</item>
@@ -1564,6 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. töö <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. töö <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Kõik muudatused lähevad kaotsi ja demo käivitub uuesti <xliff:g id="TIMEOUT">%1$s</xliff:g> sekundi möödudes …"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Tühista"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Lähtesta kohe"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Seadme piiranguteta kasutamiseks lähtestage see tehaseandmetele"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Lisateabe saamiseks puudutage."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Keelatud <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konverentskõne"</string>
+    <!-- no translation found for tooltip_popup_title (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index 6ccd864..5ee9843 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Zuk ezer egin beharrik gabe deiak egiteko IMS zerbitzua erabiltzea baimentzen die aplikazioei."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"telefonoaren egoera eta identitatea irakurtzea"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Gailuaren telefono-eginbideak atzitzeko baimena ematen die aplikazioei. Baimen horrek aplikazioari telefono-zenbakia eta gailu IDak zein diren, deirik aktibo dagoen eta deia zer zenbakirekin konektatuta dagoen zehazteko baimena ematen die aplikazioei."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"Irakurri telefono-zenbakia"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Gailuaren telefono-zenbakia atzitzea baimentzen dio aplikazioari."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"Eragotzi tableta inaktibo ezartzea"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"Eragotzi telebista inaktibo geratzea"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"Eragotzi telefonoa inaktibo ezartzea"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Laneko 2. <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Laneko 3. <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Aldaketak galduko dituzu eta <xliff:g id="TIMEOUT">%1$s</xliff:g> segundo barru hasiko da berriro demoa…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Utzi"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Berrezarri"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Berrezarri jatorrizko ezarpenak gailua murriztapenik gabe erabili ahal izateko"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Sakatu informazio gehiago lortzeko."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index e8e61f4..f10fa72 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"‏به برنامه اجازه می‌دهد از سرویس IMS برای برقراری تماس‌ها بدون دخالت شما استفاده کند."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"خواندن وضعیت تلفن و شناسه"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"به برنامه اجازه می‌دهد به ویژگی‌های تلفن دستگاه شما دسترسی پیدا کند. این مجوز به برنامه اجازه می‌دهد شماره تلفن و شناسه‌های دستگاه، فعال بودن یک تماس و شماره راه دوری که با یک تماس متصل شده است را مشخص کند."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"خواندن شماره تلفن"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"به برنامه اجازه می‌دهد به شماره تلفن دستگاه دسترسی پیدا کند."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ممانعت از به خواب رفتن رایانهٔ لوحی"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"جلوگیری از به حالت خواب رفتن تلویزیون"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ممانعت از به خواب رفتن تلفن"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"کار دوم <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"کار سوم <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"همه تغییرات را از دست خواهید داد و نسخه نمایشی دوباره تا <xliff:g id="TIMEOUT">%1$s</xliff:g> ثانیه دیگر شروع می‌شود…‏"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"لغو"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"بازنشانی در این لحظه"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"برای استفاده بدون محدودیت از این دستگاه، بازنشانی کارخانه‌ای انجام دهید"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"برای یادگیری بیشتر لمس کنید."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index dbfd8ba..05fe294 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Antaa sovelluksen soittaa puheluita pikaviestipalvelun avulla ilman käyttäjän toimia."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"lue puhelimen tila ja identiteetti"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Antaa sovelluksen käyttää laitteen puhelinominaisuuksia. Sovellus voi määrittää puhelinnumeron ja laitteen tunnuksen, puhelun tilan sekä soitetun numeron."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"lukea puhelinnumeron"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Anna sovelluksen käyttää laitteen puhelinnumeroa."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"estä tablet-laitetta menemästä virransäästötilaan"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"Estä television siirtyminen virransäästötilaan"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"estä puhelinta menemästä virransäästötilaan"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Toinen <xliff:g id="LABEL">%1$s</xliff:g>, työ"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Kolmas <xliff:g id="LABEL">%1$s</xliff:g>, työ"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Muutokset poistetaan ja esittely aloitetaan uudelleen <xliff:g id="TIMEOUT">%1$s</xliff:g> sekunnin kuluttua…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Peruuta"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Palauta nyt"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Palauta tehdasasetukset, jotta voit käyttää tätä laitetta rajoituksitta"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Lue lisätietoja koskettamalla."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 501627d..1ab43ff 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permet à l\'application d\'utiliser le service IMS pour faire des appels sans votre intervention."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"voir l\'état et l\'identité du téléphone"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permet à l\'application d\'accéder aux fonctionnalités téléphoniques de l\'appareil. Cette autorisation permet à l\'application de déterminer le numéro de téléphone et les identifiants de l\'appareil, si un appel est actif et le numéro distant connecté par un appel."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"lire le numéro de téléphone"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Permet à l\'application d\'accéder au numéro de téléphone de l\'appareil."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"empêcher la tablette de passer en mode veille"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"empêcher le téléviseur de passer en mode veille"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"empêcher le téléphone de passer en mode veille"</string>
@@ -1059,16 +1061,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Volume"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume des notifications"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Sonnerie par défaut"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Défaut (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Aucune"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Sonneries"</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 d\'alarme"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sons de notification"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Inconnu"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">Réseau Wi-Fi à proximité</item>
       <item quantity="other">Réseaux Wi-Fi à proximité</item>
@@ -1564,6 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2e <xliff:g id="LABEL">%1$s</xliff:g> professionnel(le)"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3e <xliff:g id="LABEL">%1$s</xliff:g> professionnel(le)"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Vous perdrez vos modifications, et la démo recommencera dans <xliff:g id="TIMEOUT">%1$s</xliff:g> secondes…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Annuler"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Réinitialiser maintenant"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Rétablissez la configuration d\'usine de cet appareil pour l\'utiliser sans restrictions"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Touchez ici pour en savoir plus."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Désactivé : <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conférence téléphonique"</string>
+    <!-- no translation found for tooltip_popup_title (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index ccff4f3..bdd52c6 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permet à l\'application d\'utiliser le service IMS pour passer des appels sans votre intervention."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"Voir l\'état et l\'identité du téléphone"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permet à l\'application d\'accéder aux fonctionnalités téléphoniques de l\'appareil. Cette autorisation permet à l\'application de déterminer le numéro de téléphone et les identifiants de l\'appareil, si un appel est actif et le numéro distant connecté par un appel."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"lire le numéro de téléphone"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Permet à l\'application d\'accéder au numéro de téléphone de l\'appareil."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"empêcher la tablette de passer en mode veille"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"empêcher l\'activation du mode veille sur le téléviseur"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"empêcher le téléphone de passer en mode veille"</string>
@@ -1059,16 +1061,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Volume"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume des notifications"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Sonnerie par défaut"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Sonnerie par défaut (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Aucune"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Sonneries"</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\'alarme"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sons de notification"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Inconnue"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">Réseau Wi-Fi disponible</item>
       <item quantity="other">Réseaux Wi-Fi disponibles</item>
@@ -1564,6 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2e <xliff:g id="LABEL">%1$s</xliff:g> professionnelle"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3e <xliff:g id="LABEL">%1$s</xliff:g> professionnelle"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Vous perdrez vos modifications, et la démo recommencera dans <xliff:g id="TIMEOUT">%1$s</xliff:g> secondes…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Annuler"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Réinitialiser maintenant"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Rétablir la configuration d\'usine pour utiliser cet appareil sans restrictions"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Appuyez ici pour en savoir plus."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Élément \"<xliff:g id="LABEL">%1$s</xliff:g>\" désactivé"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conférence téléphonique"</string>
+    <!-- no translation found for tooltip_popup_title (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 89a9471..b6095eb 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permite que a aplicación use o servizo de IMS para facer chamadas sen a túa intervención."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"ler o estado e a identidade do teléfono"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite á aplicación acceder ás funcións de teléfono do dispositivo. Con este permiso a aplicación pode determinar o número de teléfono e os ID do dispositivo, se unha chamada está activa e o número remoto conectado mediante unha chamada."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ler número de teléfono"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Permite que a aplicación acceda ao número de teléfono do dispositivo."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"evitar que a tableta entre en modo de inactividade"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"evitar que a televisión entre en modo de suspensión"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"evitar que o teléfono entre en modo de suspensión"</string>
@@ -551,7 +553,7 @@
     <item msgid="7897544654242874543">"Traballo"</item>
     <item msgid="1103601433382158155">"Fax do traballo"</item>
     <item msgid="1735177144948329370">"Fax particular"</item>
-    <item msgid="603878674477207394">"Busca"</item>
+    <item msgid="603878674477207394">"Buscapersoas"</item>
     <item msgid="1650824275177931637">"Outros"</item>
     <item msgid="9192514806975898961">"Personalizado"</item>
   </string-array>
@@ -594,7 +596,7 @@
     <string name="phoneTypeWork" msgid="8863939667059911633">"Traballo"</string>
     <string name="phoneTypeFaxWork" msgid="3517792160008890912">"Fax do traballo"</string>
     <string name="phoneTypeFaxHome" msgid="2067265972322971467">"Fax particular"</string>
-    <string name="phoneTypePager" msgid="7582359955394921732">"Busca"</string>
+    <string name="phoneTypePager" msgid="7582359955394921732">"Buscapersoas"</string>
     <string name="phoneTypeOther" msgid="1544425847868765990">"Outro"</string>
     <string name="phoneTypeCallback" msgid="2712175203065678206">"Devolver chamada"</string>
     <string name="phoneTypeCar" msgid="8738360689616716982">"Coche"</string>
@@ -606,7 +608,7 @@
     <string name="phoneTypeTelex" msgid="3367879952476250512">"Télex"</string>
     <string name="phoneTypeTtyTdd" msgid="8606514378585000044">"TTY TDD"</string>
     <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"Móbil do traballo"</string>
-    <string name="phoneTypeWorkPager" msgid="649938731231157056">"Busca do traballo"</string>
+    <string name="phoneTypeWorkPager" msgid="649938731231157056">"Buscapersoas do traballo"</string>
     <string name="phoneTypeAssistant" msgid="5596772636128562884">"Asistente"</string>
     <string name="phoneTypeMms" msgid="7254492275502768992">"MMS"</string>
     <string name="eventTypeCustom" msgid="7837586198458073404">"Personalizados"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> do segundo traballo"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> do terceiro traballo"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Perderás os cambios que fixeses e a demostración volverá comezar en <xliff:g id="TIMEOUT">%1$s</xliff:g> segundos…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Cancelar"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Restablecer agora"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Restablecemento dos valores de fábrica para usar este dispositivo sen restricións"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toca para acceder a máis información"</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index cbb0d9e4a4..bde7708 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"તમારા હસ્તક્ષેપ વગર કૉલ્સ કરવા માટે IMS સેવાનો ઉપયોગ કરવાની એપ્લિકેશનને મંજૂરી આપે છે."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"ફોન સ્થિતિ અને ઓળખ વાંચો"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"એપ્લિકેશનને ફોન સુવિધાઓને ઍક્સેસ કરવાની મંજૂરી આપે છે. આ પરવાનગી એપ્લિકેશનને ફોન નંબર અને ઉપકરણ ID, કૉલ સક્રિય છે અને કોઈ કૉલ દ્વારા કનેક્ટ થયેલ રિમોટ નંબર નિર્ધારિત કરવાની મંજૂરી આપે છે."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ફોન નંબર વાંચવા"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"ઍપ્લિકેશનને ઉપકરણના ફોન નંબરને ઍક્સેસ કરવાની મંજૂરી આપે છે."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ટેબ્લેટને નિષ્ક્રિય થતું અટકાવો"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"ટીવીને નિષ્ક્રિય થતો અટકાવો"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ફોનને નિષ્ક્રિય થતો અટકાવો"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2જું કાર્ય <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3જું કાર્ય <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"તમે કોઈપણ ફેરફારો ગુમાવશો અને ડેમો <xliff:g id="TIMEOUT">%1$s</xliff:g> સેકન્ડમાં ફરી શરૂ થશે…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"રદ કરો"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"હમણાં ફરીથી સેટ કરો"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"આ ઉપકરણનો પ્રતિબંધો વિના ઉપયોગ કરવા માટે ફેક્ટરી રીસેટ કરો"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"વધુ જાણવા માટે ટચ કરો."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index e833052..cb972db 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"आपके हस्‍तक्षेप के बिना कॉल करने के लिए, ऐप को IMS सेवा का उपयोग करने देती है."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"फ़ोन की स्‍थिति और पहचान पढ़ें"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"ऐप्स  को डिवाइस की फ़ोन सुविधाओं तक पहुंचने देता है. यह अनुमति ऐप्स  को फ़ोन नंबर और डिवाइस आईडी, कॉल सक्रिय है या नहीं, और कॉल द्वारा कनेक्ट किया गया दूरस्‍थ नंबर निर्धारित करने देती है."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"फ़ोन नंबर पढ़ें"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"ऐप्लिकेशन को डिवाइस का फ़ोन नंबर एक्सेस करने देती है."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"टेबलेट को निष्‍क्रिय होने से रोकें"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"टीवी को निष्‍क्रिय होने से रोकना"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"फ़ोन को निष्‍क्रिय होने से रोकें"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"दूसरा कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"तीसरा कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"आपके सभी बदलाव खो जाएंगे और डेमो <xliff:g id="TIMEOUT">%1$s</xliff:g> सेकंड में फिर से शुरू हो जाएगा…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"अभी नहीं"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"अभी रीसेट करें"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"इस डिवाइस को प्रतिबंधों के बिना उपयोग करने के लिए फ़ैक्टरी रीसेट करें"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"अधिक जानने के लिए स्पर्श करें."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index e811b94..ca8ef72 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -380,6 +380,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Omogućuje aplikaciji upotrebu usluge izravnih poruka za uspostavljanje poziva bez vaše intervencije."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"čitanje statusa i identiteta telefona"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Aplikaciji omogućuje pristup telefonskim značajkama uređaja. Ta dozvola aplikaciji omogućuje utvrđivanje telefonskog broja i ID-ova uređaja, je li poziv aktivan te udaljeni broj koji je povezan pozivom."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"čitati telefonski broj"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Omogućuje aplikaciji da pristupi telefonskom broju uređaja."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"spriječi mirovanje tabletnog uređaja"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"sprječavanje mirovanja televizora"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"sprečava telefon da prijeđe u stanje mirovanja"</string>
@@ -646,7 +648,7 @@
     <string name="relationTypeAssistant" msgid="6274334825195379076">"Pomoćnik"</string>
     <string name="relationTypeBrother" msgid="8757913506784067713">"Brat"</string>
     <string name="relationTypeChild" msgid="1890746277276881626">"Dijete"</string>
-    <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"Partner u kućan."</string>
+    <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"Vanbračni partner"</string>
     <string name="relationTypeFather" msgid="5228034687082050725">"Otac"</string>
     <string name="relationTypeFriend" msgid="7313106762483391262">"Prijatelj"</string>
     <string name="relationTypeManager" msgid="6365677861610137895">"Voditelj"</string>
@@ -1082,16 +1084,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 +1589,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. <xliff:g id="LABEL">%1$s</xliff:g> za posao"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. <xliff:g id="LABEL">%1$s</xliff:g> za posao"</string>
     <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>
@@ -1717,8 +1717,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Sve će se promjene izbrisati, a demonstracija će se ponovo pokrenuti za <xliff:g id="TIMEOUT">%1$s</xliff:g> s…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Odustani"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Vrati na zadano sada"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Uređaj je vraćen na tvorničke postavke da biste ga mogli upotrebljavati bez ograničenja"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Dodirnite da biste saznali više."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index b0ce160..d2211d8 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Az alkalmazás az IMS-szolgáltatást használhatja híváskezdeményezéshez az Ön közbeavatkozása nélkül."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"telefonállapot és azonosító olvasása"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Lehetővé teszi az alkalmazás számára, hogy hozzáférjen az eszköz telefonálási funkcióihoz. Az engedéllyel rendelkező alkalmazás meghatározhatja a telefonszámot és eszközazonosítókat, hogy egy hívás aktív-e, valamint híváskor a másik fél telefonszámát."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"telefonszám beolvasása"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Engedélyezi az alkalmazás számára, hogy hozzáférjen az eszköz telefonszámához."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"táblagép alvás üzemmódjának megakadályozása"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"a tévé alvó üzemmódba való lépésének megakadályozása"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"telefon alvó üzemmódjának megakadályozása"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. munkahelyi <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. munkahelyi <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"A módosítások elvesznek, és a bemutató újra elindul <xliff:g id="TIMEOUT">%1$s</xliff:g> másodperc múlva…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Mégse"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Visszaállítás most"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Állítsa vissza a gyári beállításokat az eszköz korlátozások nélküli használata érdekében"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Érintse meg a további információkért."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 2ba22af..d309ce4 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Թույլ է տալիս հավելվածին IMS ծառայության միջոցով կատարել զանգեր՝ առանց ձեր միջամտության:"</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"կարդալ հեռախոսի կարգավիճակը և ինքնությունը"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Թույլ է տալիս հավելվածին օգտագործել սարքի հեռախոսային գործիքները: Այս թույլտվությունը հավելվածին հնարավորություն է տալիս որոշել հեռախոսահամարը և սարքի ID-ները, արդյոք զանգը ակտիվ է և միացված զանգի հեռակա հեռախոսահամարը:"</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"կարդալ հեռախոսահամարը"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Հավելվածին թույլ է տալիս օգտագործել սարքի հեռախոսահամարը:"</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"զերծ պահել պլանշետը քնելուց"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"թույլ չտալ հեռուստացույցին մտնել քնի ռեժիմ"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"կանխել հեռախոսի քնի ռեժիմին անցնելը"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2-րդ աշխատանք <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3-րդ աշխատանք <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Կատարված փոփոխությունները չեն պահվի, իսկ ցուցադրական նյութը կրկին կգործարկվի <xliff:g id="TIMEOUT">%1$s</xliff:g> վայրկյանից…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Չեղարկել"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Վերակայել հիմա"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Սարքն առանց սահմանափակումների օգտագործելու համար կատարեք գործարանային վերակայում"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Հպեք՝ ավելին իմանալու համար:"</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 09223cd..ae034c1 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Memungkinkan aplikasi menggunakan layanan IMS untuk melakukan panggilan tanpa campur tangan Anda."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"baca identitas dan status ponsel"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Memungkinkan aplikasi mengakses fitur telepon perangkat. Izin ini memungkinkan aplikasi menentukan nomor telepon dan ID perangkat, apakah suatu panggilan aktif atau tidak, dan nomor jarak jauh yang tersambung oleh sebuah panggilan."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"baca nomor telepon"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Mengizinkan aplikasi mengakses nomor telepon perangkat ini."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"cegah tablet dari tidur"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"cegah agar TV tidak tidur"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"mencegah ponsel menjadi tidak aktif"</string>
@@ -988,7 +990,7 @@
     <string name="whichImageCaptureApplicationLabel" msgid="6390303445371527066">"Jepret gambar"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Gunakan secara default untuk tindakan ini."</string>
     <string name="use_a_different_app" msgid="8134926230585710243">"Gunakan aplikasi yang berbeda"</string>
-    <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Menghapus default di Setelan sistem &gt; Apl &gt; Terunduh."</string>
+    <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Menghapus default di Setelan sistem &gt; Apl &gt; Terdownload."</string>
     <string name="chooseActivity" msgid="7486876147751803333">"Pilih tindakan"</string>
     <string name="chooseUsbActivity" msgid="6894748416073583509">"Pilih apl untuk perangkat USB"</string>
     <string name="noApplications" msgid="2991814273936504689">"Tidak ada apl yang dapat melakukan tindakan ini."</string>
@@ -1016,7 +1018,7 @@
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> telah diluncurkan aslinya."</string>
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skala"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Selalu tampilkan"</string>
-    <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktifkan kembali dialog ini di Setelan sistem &gt; Apl &gt; Terunduh."</string>
+    <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktifkan kembali dialog ini di Setelan sistem &gt; Apl &gt; Terdownload."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak mendukung setelan Ukuran layar saat ini dan dapat menunjukkan perilaku yang tak diharapkan."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Selalu tampilkan"</string>
     <string name="smv_application" msgid="3307209192155442829">"Apl <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) telah melanggar kebijakan StrictMode yang diberlakukannya sendiri."</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Upaya ke-2 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Upaya ke-3 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Perubahan yang dibuat akan hilang dan demo akan dimulai lagi dalam <xliff:g id="TIMEOUT">%1$s</xliff:g> detik…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Batal"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Setel ulang sekarang"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Dikembalikan ke setelan pabrik agar perangkat ini dapat digunakan tanpa batasan"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Sentuh untuk mempelajari lebih lanjut."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 105a647..6154e12 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Leyfir forriti að nota IMS-þjónustu til að hringja án inngrips frá þér."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"lesa stöðu símans og auðkenni"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Leyfir forriti að fá aðgang að símaeiginleikum tækisins. Þessi heimild gerir forritinu kleift að komast að símanúmeri og auðkennum tækisins, hvort símtal er í gangi og símanúmeri viðmælanda í símtali."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"lesa símanúmer"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Veitir forritinu aðgang að símanúmeri tækisins."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"koma í veg fyrir að spjaldtölvan fari í biðstöðu"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"koma í veg fyrir að sjónvarpið fari í biðstöðu"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"koma í veg fyrir að síminn fari í biðstöðu"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> í vinnu (2)"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> í vinnu (3)"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Þú glatar öllum breytingum og kynningin byrjar aftur eftir <xliff:g id="TIMEOUT">%1$s</xliff:g> sekúndur…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Hætta við"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Endurstilla núna"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Núllstilltu til að nota þetta tæki án takmarkana"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Snertu til að fá frekari upplýsingar."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 564472e..4e9a3bf 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Consente all\'app di utilizzare il servizio IMS per fare chiamate senza il tuo intervento."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"lettura stato e identità telefono"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Consente all\'applicazione di accedere alle funzioni telefoniche del dispositivo. Questa autorizzazione consente all\'applicazione di determinare il numero di telefono e gli ID dei dispositivi, se una chiamata è attiva e il numero remoto connesso da una chiamata."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"leggi il numero di telefono"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Consente all\'app di accedere al numero di telefono del dispositivo."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"disattivazione stand-by del tablet"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"divieto di attivazione della modalità di sospensione della TV"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"disattivazione stand-by del telefono"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> di lavoro (2°)"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> di lavoro (3°)"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Perderai tutte le modifiche e la demo verrà riavviata tra <xliff:g id="TIMEOUT">%1$s</xliff:g> secondi…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Annulla"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Ripristina ora"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Esegui il ripristino dei dati di fabbrica per utilizzare il dispositivo senza limitazioni"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Tocca per ulteriori informazioni."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index d4b9bf1..427832c 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -383,6 +383,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"‏מאפשר לאפליקציה להשתמש בשירות ה-IMS לביצוע שיחות ללא התערבותך."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"קריאת הסטטוס והזהות של הטלפון"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"מאפשר לאפליקציה לגשת לתכונות הטלפון של המכשיר. אישור זה מתיר לאפליקציה לגלות את מספר הטלפון ואת זיהויי המכשיר, האם שיחה פעילה ואת המספר המרוחק המחובר באמצעות שיחה."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"קריאת מספר טלפון"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"מאפשרת לאפליקציה לגשת למספר הטלפון של המכשיר."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"מנע מהטאבלט לעבור למצב שינה"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"מניעת מעבר למצב שינה בטלוויזיה"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"מניעת מעבר הטלפון למצב שינה"</string>
@@ -599,7 +601,7 @@
     <string name="phoneTypeMobile" msgid="6501463557754751037">"נייד"</string>
     <string name="phoneTypeWork" msgid="8863939667059911633">"עבודה"</string>
     <string name="phoneTypeFaxWork" msgid="3517792160008890912">"פקס בעבודה"</string>
-    <string name="phoneTypeFaxHome" msgid="2067265972322971467">"מס\' פקס בבית"</string>
+    <string name="phoneTypeFaxHome" msgid="2067265972322971467">"פקס בבית"</string>
     <string name="phoneTypePager" msgid="7582359955394921732">"זימונית"</string>
     <string name="phoneTypeOther" msgid="1544425847868765990">"אחר"</string>
     <string name="phoneTypeCallback" msgid="2712175203065678206">"התקשרות חזרה"</string>
@@ -612,7 +614,7 @@
     <string name="phoneTypeTelex" msgid="3367879952476250512">"טלקס"</string>
     <string name="phoneTypeTtyTdd" msgid="8606514378585000044">"TTY TDD"</string>
     <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"נייד של העבודה"</string>
-    <string name="phoneTypeWorkPager" msgid="649938731231157056">"איתורית של העבודה"</string>
+    <string name="phoneTypeWorkPager" msgid="649938731231157056">"זימונית מהעבודה"</string>
     <string name="phoneTypeAssistant" msgid="5596772636128562884">"מסייע"</string>
     <string name="phoneTypeMms" msgid="7254492275502768992">"MMS"</string>
     <string name="eventTypeCustom" msgid="7837586198458073404">"מותאם אישית"</string>
@@ -1105,16 +1107,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="two">‏יש רשתות Wi-Fi זמינות</item>
       <item quantity="many">‏יש רשתות Wi-Fi זמינות</item>
@@ -1618,6 +1616,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> שני בעבודה"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> שלישי בעבודה"</string>
     <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>
@@ -1753,8 +1753,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"תאבד את כל השינויים וההדגמה תתחיל שוב בעוד <xliff:g id="TIMEOUT">%1$s</xliff:g> שניות…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"בטל"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"אפס עכשיו"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"איפוס להגדרות היצרן כדי לאפשר שימוש במכשיר ללא מגבלות"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"גע לקבלת מידע נוסף."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index e2432f1..2f09977 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"IMSサービスがユーザー操作なしで電話をかけることをアプリに許可します。"</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"端末情報と ID の読み取り"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"端末の電話機能へのアクセスをアプリに許可します。これにより、電話番号、端末ID、通話中かどうか、通話相手の電話番号をアプリから特定できるようになります。"</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"電話番号の読み取り"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"端末の電話番号へのアクセスをアプリに許可します。"</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"タブレットのスリープを無効化"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"テレビのスリープを無効化"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"端末のスリープを無効にする"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2 番目の仕事用<xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3 番目の仕事用<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"変更が失われ、<xliff:g id="TIMEOUT">%1$s</xliff:g> 秒後にデモがもう一度開始されます…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"キャンセル"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"今すぐリセット"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"制限なしでこの端末を使用するには初期状態にリセットしてください"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"タップして詳細をご確認ください。"</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 5e069b6..1686591 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"აპს შეეძლება, გამოიყენოს IMS სერვისი ზარების თქვენი ჩარევის გარეშე განსახორციელებლად."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"ტელეფონის სტატუსისა და იდენტობის წაკითხვა"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"აპს შეეძლება ჰქონდეს წვდომა მოწყობილობის სატელეფონო ფუნქციებზე. აპმა მსგავსი უფლებით შეძლებს დაადგინოს ტელეფონის ნომერი, მისი სერიული გამოცემა, აქტიური ზარი, დაკავშირებული ნომერი და მსგავსი."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ტელეფონის ნომრის წაკითხვა"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"აპს მოწყობილობის ტელეფონის ნომერზე წვდომის საშუალებას მისცემს."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"დაიცავით ტაბლეტი დაძინებისგან"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"ტელევიზორის დაცვა დაძინებისაგან"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ტელეფონის ძილის რეჟიმში გადასვლის აღკვეთა"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"მე-2 სამსახური <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"მე-3 სამსახური <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"შეტანილი ცვლილებები დაიკარგება, ხოლო დემონსტრაცია ხელახლა <xliff:g id="TIMEOUT">%1$s</xliff:g> წამში დაიწყება…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"გაუქმება"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"ახლავე გადაყენება"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"ამ მოწყობილობის შეზღუდვების გარეშე გამოსაყენებლად, დააბრუნეთ ქარხნული პარამეტრები"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"შეეხეთ მეტის გასაგებად."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index 729f726..210fd01 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Сіздің қатысуыңызсыз қоңыраулар соғу үшін қолданбаға IMS қызметін пайдалануға рұқсат етеді."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"телефон күйін оқу немесе анықтау"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Қолданбаға құрылғыдағы телефон функцияларына кіру мүмкіндігін береді. Бұл рұқсат қолданбаға телефон нөмірі, құрылғы жеке анықтағышы, қоңырау белсенділігі және сол қоңырауға байланысты қашықтағы нөмірді анықтау мүмкіндігін береді."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"телефон нөмірін оқу"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Қолданбаға құрылғының телефон нөмірін алуға рұқсат береді."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"планшетті ұйқыдан бөгеу"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"ТД ұйықтауын болдырмау"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"телефонды ұйқыдан бөгеу"</string>
@@ -1059,16 +1061,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Meдиа дыбысының қаттылығы"</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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2-ші жұмыс профилі (<xliff:g id="LABEL">%1$s</xliff:g>)"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3-ші жұмыс профилі (<xliff:g id="LABEL">%1$s</xliff:g>)"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Барлық өзгеріс жоғалады және демо нұсқасы <xliff:g id="TIMEOUT">%1$s</xliff:g> секундтан кейін қайта қосылады…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Бас тарту"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Қазір бастапқы күйге қайтару"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Осы құрылғыны шектеусіз пайдалану үшін зауыттық параметрлерді қалпына келтіріңіз"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Қосымша мәліметтер алу үшін түртіңіз."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index c3e939e..04e7681 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"អនុញ្ញាតឲ្យកម្មវិធីនេះប្រើសេវាកម្ម IMS ដើម្បីធ្វើការហៅដោយគ្មានការអន្តរាគមន៍ពីអ្នក។"</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"អាន​ស្ថានភាព និង​អត្តសញ្ញាណ​ទូរស័ព្ទ"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"ឲ្យ​កម្មវិធី​ចូល​ដំណើរការ​លក្ខណៈ​ទូរស័ព្ទ​នៃ​ឧបករណ៍។ សិទ្ធិ​នេះ​​ឲ្យ​កម្មវិធី​កំណត់​លេខ​ទូរស័ព្ទ និង​លេខ​សម្គាល់​ឧបករណ៍ ថា​តើ​ការ​ហៅ​សកម្ម និង​លេខ​ពី​ចម្ងាយ​បាន​ភ្ជាប់​ដោយ​ការ​ហៅ។"</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"អានលេខទូរសព្ទ"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"អនុញ្ញាតឲ្យកម្មវិធីនេះចូលប្រើលេខទូរសព្ទរបស់ឧបករណ៍នេះ។"</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ការពារ​​កុំព្យូទ័រ​បន្ទះ​មិន​ឲ្យ​ដេក"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"បង្ការទូរទស្សន៍ពីការបិទពន្លឺ"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ការ​ពារ​ទូរស័ព្ទ​មិន​ឲ្យ​ដេក"</string>
@@ -605,9 +607,9 @@
     <string name="phoneTypeRadio" msgid="4093738079908667513">"វិទ្យុ"</string>
     <string name="phoneTypeTelex" msgid="3367879952476250512">"ទូរសារ"</string>
     <string name="phoneTypeTtyTdd" msgid="8606514378585000044">"TTY TDD"</string>
-    <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"ទូរស័ព្ទ​​កន្លែងធ្វើការ"</string>
+    <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"ទូរសព្ទ​​កន្លែងធ្វើការ"</string>
     <string name="phoneTypeWorkPager" msgid="649938731231157056">"ភេយ័រ​កន្លែង​ធ្វើ​ការ"</string>
-    <string name="phoneTypeAssistant" msgid="5596772636128562884">"អ្នក​ជំនួយ​ការ"</string>
+    <string name="phoneTypeAssistant" msgid="5596772636128562884">"ជំនួយ​ការ"</string>
     <string name="phoneTypeMms" msgid="7254492275502768992">"សារ MMS"</string>
     <string name="eventTypeCustom" msgid="7837586198458073404">"តាម​តម្រូវ​ការ"</string>
     <string name="eventTypeBirthday" msgid="2813379844211390740">"ថ្ងៃ​ខួប​កំណើត"</string>
@@ -640,10 +642,10 @@
     <string name="orgTypeOther" msgid="3951781131570124082">"ផ្សេងៗ"</string>
     <string name="orgTypeCustom" msgid="225523415372088322">"តាម​តម្រូវការ"</string>
     <string name="relationTypeCustom" msgid="3542403679827297300">"តាម​បំណង"</string>
-    <string name="relationTypeAssistant" msgid="6274334825195379076">"អ្នក​ជំនួយ​ការ"</string>
+    <string name="relationTypeAssistant" msgid="6274334825195379076">"ជំនួយ​ការ"</string>
     <string name="relationTypeBrother" msgid="8757913506784067713">"បងប្អូន​ប្រុស"</string>
     <string name="relationTypeChild" msgid="1890746277276881626">"កូន"</string>
-    <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"ដៃគូ​ក្នុងស្រុក"</string>
+    <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"ដៃគូ​រួមរស់ជាមួយគ្នា"</string>
     <string name="relationTypeFather" msgid="5228034687082050725">"ឪពុក"</string>
     <string name="relationTypeFriend" msgid="7313106762483391262">"មិត្តភ័ក្ដិ"</string>
     <string name="relationTypeManager" msgid="6365677861610137895">"អ្នក​គ្រប់គ្រង"</string>
@@ -1061,16 +1063,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>
@@ -1566,6 +1564,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> ការងារទី 2"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> ការងារទី 3"</string>
     <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,8 +1683,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"អ្នកនឹងបាត់បង់ការផ្លាស់ប្តូរណាមួយ ហើយការបង្ហាញសាកល្បងនឹងចាប់ផ្តើមម្តងទៀតក្នុងរយៈពេល <xliff:g id="TIMEOUT">%1$s</xliff:g> វិនាទីទៀត…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"បោះបង់"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"កំណត់ឡើងវិញឥឡូវនេះ"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"កំណត់ដូចចេញពីរោងចក្រឡើងវិញដើម្បីប្រើឧបករណ៍នេះដោយគ្មានការរឹតបន្តឹង"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"ប៉ះ​ ដើម្បី​​ស្វែងយល់​បន្ថែម។"</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index 7f80a29..21cf1ba 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"ನಿಮ್ಮ ಮಧ್ಯಸ್ಥಿಕೆ ಇಲ್ಲದೆಯೇ ಕರೆಗಳನ್ನು ಮಾಡಲು IMS ಸೇವೆಯನ್ನು ಬಳಸಲು ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಅನುಮತಿಸುತ್ತದೆ."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"ಫೋನ್ ಸ್ಥಿತಿ ಮತ್ತು ಗುರುತಿಸುವಿಕೆಯನ್ನು ಓದಿ"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"ಸಾಧನದ ಫೋನ್ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಪ್ರವೇಶಿಸಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಈ ಅನುಮತಿಯು ಫೋನ್ ಸಂಖ್ಯೆ ಮತ್ತು ಸಾಧನದ ID ಗಳನ್ನು ನಿರ್ಧರಿಸಲು, ಕರೆಯು ಸಕ್ರಿಯವಾಗಿದೆಯೇ ಮತ್ತು ಕರೆಯ ಮೂಲಕ ರಿಮೋಟ್ ಸಂಖ್ಯೆಯು ಸಂಪರ್ಕಗೊಂಡಿವೆಯೇ ಎಂಬುದನ್ನೂ ನಿರ್ಧರಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅವಕಾಶ ಕಲ್ಪಿಸುತ್ತದೆ."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ಫೋನ್ ಸಂಖ್ಯೆ ಓದಿ"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"ಸಾಧನದ ಫೋನ್ ಸಂಖ್ಯೆ ಪ್ರವೇಶಿಸಲು ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಅನುಮತಿಸುತ್ತದೆ."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ಟ್ಯಾಬ್ಲೆಟ್ ನಿದ್ರಾವಸ್ಥೆಯನ್ನು ತಡೆಯಿರಿ"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"ಟಿವಿಗೆ ನಿದ್ರಿಸುವುದನ್ನು ತಪ್ಪಿಸಿ"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ಫೋನ್ ಆಫ್ ಆಗುವುದರಿಂದ ತಡೆಯಿರಿ"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2 ನೇ ಕೆಲಸದ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3 ನೇ ಕೆಲಸದ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"ನೀವು ಯಾವುದೇ ಬದಲಾವಣೆಗಳನ್ನು ಕಳೆದುಕೊಳ್ಳುತ್ತೀರಿ ಮತ್ತು <xliff:g id="TIMEOUT">%1$s</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಡೆಮೋ ಮತ್ತೆ ಪ್ರಾರಂಭವಾಗುತ್ತದೆ..."</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"ರದ್ದುಮಾಡಿ"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"ಈಗಲೇ ಮರುಹೊಂದಿಸು"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"ನಿರ್ಬಂಧಗಳು ಇಲ್ಲದೆಯೇ ಈ ಸಾಧನವನ್ನು ಬಳಸಲು ಫ್ಯಾಕ್ಟರಿ ಮರುಹೊಂದಿಸಿ"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"ಇನ್ನಷ್ಟು ತಿಳಿಯಲು ಸ್ಪರ್ಶಿಸಿ."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 444c83d..70388bf 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"앱이 IMS 서비스를 사용하여 자동으로 전화를 걸 수 있도록 허용합니다."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"휴대전화 상태 및 ID 읽기"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"앱이 기기의 휴대전화 기능에 액세스할 수 있도록 허용합니다. 이 권한을 사용하면 앱이 전화번호 및 기기의 ID, 활성 통화인지 여부, 통화가 연결된 원격 번호 등을 확인할 수 있습니다."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"전화번호 읽기"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"앱에서 기기의 전화번호에 액세스할 수 있도록 허용합니다."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"태블릿이 절전 모드로 전환되지 않도록 설정"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"TV의 절전 모드 전환 방지"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"휴대전화가 절전 모드로 전환되지 않도록 설정"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"두번째 작업 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"세번째 작업<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"변경사항이 사라지며 데모가 <xliff:g id="TIMEOUT">%1$s</xliff:g>초 후에 시작됩니다."</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"취소"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"지금 초기화"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"제한 없이 기기를 사용하기 위한 초기화"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"자세한 내용을 보려면 터치하세요."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 2b592bd..0c799f5 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Колдонмого сизди катыштырбай туруп, IMS кызматынын жардамы менен чалууларды жасоо мүмкүнчүлүгүн берет."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"телефондун абалын жана аныктыгын окуу"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Колдонмого түзмөктүн чалуу мүмкүнчүлүктөрүнө жетки алуу уруксатын берет. Бул уруксат колдонмого, телефондун номурун, түзмөктүн ID-син, чалуунун абалын жана байланышта чыккан номурду аныктоого жол берет."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"телефон номерин окуу"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Колдонмого түзмөктүн телефон номерин окуу мүмкүнчүлүгү берилет."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"планшетти уктатпай сактоо"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"сыналгыны көшүтпөө"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"телефонду уктатпай сактоо"</string>
@@ -641,18 +643,18 @@
     <string name="orgTypeCustom" msgid="225523415372088322">"Өзгөчө"</string>
     <string name="relationTypeCustom" msgid="3542403679827297300">"Өзгөчө"</string>
     <string name="relationTypeAssistant" msgid="6274334825195379076">"Жардамчы"</string>
-    <string name="relationTypeBrother" msgid="8757913506784067713">"Ага-ини"</string>
-    <string name="relationTypeChild" msgid="1890746277276881626">"Баласы"</string>
-    <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"Жергиликтүү Өнөктөш"</string>
-    <string name="relationTypeFather" msgid="5228034687082050725">"Атасы"</string>
-    <string name="relationTypeFriend" msgid="7313106762483391262">"Досу"</string>
-    <string name="relationTypeManager" msgid="6365677861610137895">"Менежер"</string>
-    <string name="relationTypeMother" msgid="4578571352962758304">"Энеси"</string>
+    <string name="relationTypeBrother" msgid="8757913506784067713">"Ага/Ини"</string>
+    <string name="relationTypeChild" msgid="1890746277276881626">"Бала"</string>
+    <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"Жарандык нике"</string>
+    <string name="relationTypeFather" msgid="5228034687082050725">"Ата"</string>
+    <string name="relationTypeFriend" msgid="7313106762483391262">"Дос"</string>
+    <string name="relationTypeManager" msgid="6365677861610137895">"Башчы"</string>
+    <string name="relationTypeMother" msgid="4578571352962758304">"Эне"</string>
     <string name="relationTypeParent" msgid="4755635567562925226">"Ата/эне"</string>
     <string name="relationTypePartner" msgid="7266490285120262781">"Өнөк"</string>
-    <string name="relationTypeReferredBy" msgid="101573059844135524">"Төмөнкүдөй аталат"</string>
+    <string name="relationTypeReferredBy" msgid="101573059844135524">"Сунушталган"</string>
     <string name="relationTypeRelative" msgid="1799819930085610271">"Тууган"</string>
-    <string name="relationTypeSister" msgid="1735983554479076481">"Эже-сиңди"</string>
+    <string name="relationTypeSister" msgid="1735983554479076481">"Эже/Сиңди"</string>
     <string name="relationTypeSpouse" msgid="394136939428698117">"Жубай"</string>
     <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Өзгөчө"</string>
     <string name="sipAddressTypeHome" msgid="6093598181069359295">"Үй"</string>
@@ -1058,17 +1060,13 @@
     <string name="volume_icon_description_incall" msgid="8890073218154543397">"Чалуунун үн деңгээли"</string>
     <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" msgid="3789758980357696936">"Демейки шыңгыр"</string>
+    <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" msgid="3515143939175119094">"Шыңгырлар"</string>
+    <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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2-жумуш <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3-жумуш <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Бардык өзгөртүүлөр жоголуп, демо режим <xliff:g id="TIMEOUT">%1$s</xliff:g> секунддан кийин кайра башталат…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Жокко чыгаруу"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Баштапкы абалга келтирүү"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Бул түзмөктү чектөөсүз колдонуу үчүн аны баштапкы абалга келтириңиз"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Көбүрөөк билүү үчүн тийип коюңуз."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 3a96743..9e91888 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບ​ໃຊ້​ການ​ບໍ​ລິ​ການ IMS ເພື່ອ​ໂທ​ໂດຍ​ບໍ່​ມີ​ການ​ຊ່ວຍ​ເຫຼືອ​ຂອງ​ທ່ານ."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"ອ່ານສະຖານະ ແລະຂໍ້ມູນລະບຸໂຕຕົນຂອງໂທລະສັບ"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"ອະນຸຍາດໃຫ້ແອັບຯ ເຂົ້າເຖິງຄວາມສາມາດການໂທລະສັບຂອງອຸປະກອນ. ການກຳນົດສິດນີ້ເຮັດໃຫ້ແອັບຯສາມາດກວດສອບເບີໂທລະສັບ ແລະ ID ຂອງອຸປະກອນ, ບໍ່ວ່າການໂທຈະຍັງດຳເນີນຢູ່ ແລະເບີປາຍທາງເຊື່ອມຕໍ່ຢູ່ຫຼືບໍ່ກໍຕາມ."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"read phone number"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Allows the app to access the phone number of the device."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ຂັດຂວາງບໍ່ໃຫ້ປິດໜ້າຈໍແທັບເລັດ"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"ປ້ອງ​ກັນ​ບໍ່​ໃຫ້ໂທລະພາບຫຼັບ​ພັກ"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ຂັດຂວາງບໍ່ໃຫ້ໂທລະສັບປິດໜ້າຈໍ"</string>
@@ -1059,16 +1061,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">"Default (<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">"Alarm sounds"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Notification sounds"</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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"ບ່ອນເຮັດວຽກທີ 2 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"ບ່ອນເຮັດວຽກທີ 3 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"ທ່ານຈະສູນເສຍການປ່ຽນແປງ ແລະ ເດໂມຈະເລີ່ມອີກຄັ້ງໃນອີກ <xliff:g id="TIMEOUT">%1$s</xliff:g> ວິນາທີ…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"ຍົກເລີກ"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"ຣີເຊັດດຽວນີ້"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"ຣີເຊັດໃຫ້ເປັນຄ່າໂຮງງານເພື່ອໃຊ້ອຸປະກອນນີ້ໂດຍບໍ່ມີຂໍ້ຈຳກັດ"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"ແຕະເພື່ອສຶກສາເພີ່ມເຕີມ."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index d60a010..e4f3553 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -383,6 +383,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Programai leidžiama naudoti IMS paslaugą, kad būtų galima atlikti skambučius be jūsų įsikišimo."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"skaityti telefono būseną ir tapatybę"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Leidžiama programai pasiekti telefono funkcijas įrenginyje. Šis leidimas suteikia teisę programai nustatyti telefono numerį ir įrenginio ID, tai, ar skambutis aktyvus, ir skambučiu prijungtą nuotolinį numerį."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"skaityti telefono numerį"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Programai leidžiama pasiekti įrenginio telefono numerį."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"neleisti planšetiniam kompiuteriui užmigti"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"neleisti įjungti TV miego būsenos"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"neleisti telefonui snausti"</string>
@@ -1105,16 +1107,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Medijos garsumas"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Pranešimo apimtis"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Numatytasis skambėjimo tonas"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Numatytasis („<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>“)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Nėra"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Skambėjimo tonai"</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">"Įspėjimų garsai"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Pranešimų garsai"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Nežinoma"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">Pasiekiami „Wi-Fi“ tinklai</item>
       <item quantity="few">Pasiekiami „Wi-Fi“ tinklai</item>
@@ -1618,6 +1616,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2-asis darbo <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3-iasis darbo <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1753,8 +1753,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Prarasite visus pakeitimus, o demonstracinė versija bus paleista iš naujo po <xliff:g id="TIMEOUT">%1$s</xliff:g> sek…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Atšaukti"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Nustatyti iš naujo dabar"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Atkurkite gamyklinius nustatymus, kad galėtumėte naudoti šį įrenginį be apribojimų"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Palieskite, kad sužinotumėte daugiau."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Išj. valdiklis „<xliff:g id="LABEL">%1$s</xliff:g>“"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferencinis skambutis"</string>
+    <!-- no translation found for tooltip_popup_title (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 7afb2ce..1b9fdbc 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -380,6 +380,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Ļauj lietotnei izmantot tūlītējās ziņojumapmaiņas pakalpojumu, lai veiktu zvanus bez jūsu ziņas."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"lasīt tālruņa statusu un identitāti"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Ļauj lietotnei piekļūt ierīces tālruņa funkcijām. Ar šo atļauju lietotne var noteikt tālruņa numuru un ierīču ID, zvana statusu un attālo numuru, ar ko ir izveidots savienojums, veicot zvanu."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"lasīt tālruņa numuru"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Ļauj lietotnei piekļūt ierīces tālruņa numuram."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"novērst planšetdatora pāriešanu miega režīmā"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"novērst televizora pāreju miega režīmā"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"novērst tālruņa pāriešanu miega režīmā"</string>
@@ -1082,16 +1084,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Multivides skaļums"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Paziņojumu skaļums"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Noklusējuma zvana signāls"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Noklusējuma (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Nav"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Zvana signāli"</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">"Modinātāja signāla skaņas"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Paziņojumu skaņas"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Nezināms"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="zero">Pieejami Wi-Fi tīkli</item>
       <item quantity="one">Pieejami Wi-Fi tīkli</item>
@@ -1591,6 +1589,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. darba profils: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. darba profils: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1717,8 +1717,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Pēc <xliff:g id="TIMEOUT">%1$s</xliff:g> sekundēm zaudēsiet visas izmaiņas un tiks atkārtoti palaista demonstrācija..."</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Atcelt"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Atiestatīt tūlīt"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Rūpnīcas datu atiestatīšana ierīces neierobežotai izmantošanai"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Pieskarieties, lai uzzinātu vairāk."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> atspējots"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferences zvans"</string>
+    <!-- no translation found for tooltip_popup_title (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index 139e02a..7a32076 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Дозволува апликацијата да ја користи услугата IMS за повици без ваша интервенција."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"прочитај ги статусот и идентитетот  на телефонот"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Овозможува апликацијата да пристапи кон карактеристиките на телефонот на уредот. Оваа дозвола овозможува апликацијата да ги утврди телефонскиот број и ID на уредот, дали повикот е активен и далечинскиот број поврзан со повикот."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"прочитај телефонски број"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Ѝ дозволува на апликацијата да пристапи до телефонскиот број на уредот."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"спречи режим на штедење кај таблет"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"спречи го телевизорот да премине во режим на мирување"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"спречи телефон од режим на штедење"</string>
@@ -1059,16 +1061,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 +1564,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Втора деловна <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Трета деловна <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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,8 +1683,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Ќе ги изгубите измените и демонстрацијата ќе започне повторно по <xliff:g id="TIMEOUT">%1$s</xliff:g> секунди…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Откажи"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Ресетирај сега"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Ресетирајте до фабричките поставки за уредов да го користите без ограничувања"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Допрете за да дознаете повеќе."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index fc3eb40..946ac13 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -163,7 +163,7 @@
     <string name="notification_title" msgid="8967710025036163822">"<xliff:g id="ACCOUNT">%1$s</xliff:g> എന്നതിൽ സൈൻ ഇൻ ചെയ്യുന്നതിൽ പിശക്"</string>
     <string name="contentServiceSync" msgid="8353523060269335667">"സമന്വയിപ്പിക്കുക"</string>
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"സമന്വയിപ്പിക്കുക"</string>
-    <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"വളരെയധികം <xliff:g id="CONTENT_TYPE">%s</xliff:g> ഇല്ലാതാക്കലുകൾ."</string>
+    <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"വളരെയധികം <xliff:g id="CONTENT_TYPE">%s</xliff:g> ഇല്ലാതാക്കുന്നു."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"ടാബ്‌ലെറ്റ് സ്റ്റോറേജ്  കഴിഞ്ഞു. ഇടം ശൂന്യമാക്കാൻ ചില ഫയലുകൾ ഇല്ലാതാക്കുക."</string>
     <string name="low_memory" product="watch" msgid="4415914910770005166">"വാച്ചിലെ സ്റ്റോറേജ്  നിറഞ്ഞു. ഇടം ശൂന്യമാക്കാൻ കുറച്ച് ഫയലുകൾ ഇല്ലാതാക്കുക."</string>
     <string name="low_memory" product="tv" msgid="516619861191025923">"ടിവി സ്റ്റോറേജ്  നിറഞ്ഞു. ഇടം ശൂന്യമാക്കാൻ കുറച്ച് ഫയലുകൾ ഇല്ലാതാക്കുക."</string>
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"നിങ്ങളുടെ ഇടപെടൽ ഇല്ലാതെ കോളുകൾ ചെയ്യാൻ IMS സേവനം ഉപയോഗിക്കുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"ഫോൺ നിലയും ഐഡന്റിറ്റിയും റീഡുചെയ്യുക"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"ഉപകരണത്തിന്റെ ഫോൺ സവിശേഷതകൾ ആക്‌സസ്സുചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഈ അനുമതി ഫോൺ നമ്പർ, ഉപകരണ ഐഡികൾ, ഒരു കോൾ സജീവമാണോയെന്നത്, ഒരു കോൾ കണക്റ്റുചെയ്‌ത വിദൂര നമ്പർ എന്നിവ നിർണ്ണയിക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ഫോൺ നമ്പർ വായിക്കുക"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"ഉപകരണത്തിന്റെ ഫോൺ നമ്പർ ആക്സസ്സ് ചെയ്യുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"സുഷുപ്‌തിയിലാകുന്നതിൽ നിന്ന് ടാബ്‌ലെറ്റിനെ തടയുക"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"ടിവിയെ നിർജ്ജീവമാകുന്നതിൽ നിന്ന് തടയുക"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"സുഷുപ്‌തിയിലാകുന്നതിൽ നിന്ന് ഫോണിനെ തടയുക"</string>
@@ -1059,16 +1061,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">വൈഫൈ നെറ്റ്‌വർക്കുകൾ ലഭ്യമാണ്</item>
       <item quantity="one">വൈഫൈ നെറ്റ്‌വർക്ക് ലഭ്യമാണ്</item>
@@ -1564,6 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"രണ്ടാമത്തെ ഔദ്യോഗിക <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"മൂന്നാമത്തെ ഔദ്യോഗിക <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"മാറ്റങ്ങളെല്ലാം നിങ്ങൾക്ക് നഷ്ടപ്പെടും, <xliff:g id="TIMEOUT">%1$s</xliff:g> സെക്കൻഡിൽ ഡെമോ വീണ്ടും തുടങ്ങും…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"റദ്ദാക്കുക"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"ഇപ്പോൾ പുനക്രമീകരിക്കുക"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"നിയന്ത്രണങ്ങൾ ഇല്ലാതെ ഈ ഉപകരണം ഉപയോഗിക്കാൻ ഫാക്ടറി റീസെറ്റ് നടത്തുക"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"കൂടുതലറിയുന്നതിന് സ്‌പർശിക്കുക."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 2faf163..50333a8 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Апп нь дуудлага хийхдээ таны оролцоогүйгээр IMS үйлчилгээг ашиглах боломжтой."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"утасны статус ба таниулбарыг унших"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Апп нь төхөөрөмжийн утасны функцд хандах боломжтой. Энэ зөвшөөрөл нь апп-д утасны дугаар болон төхөөрөмжийн ID-г, дуудлага идэвхтэй эсэх, холын дугаар дуудлагаар холбогдсон байгаа эсэхийг тогтоох боломжийг олгоно,"</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"утасны дугаарыг харах"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Төхөөрөмжийн утасны дугаарт хандах зөвшөөрлийг аппд олгоно."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"таблетыг унтуулахгүй байлгах"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"Телевиз-ийн гэрэл унтрахаас сэргийл"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"утсыг унтуулахгүй байлгах"</string>
@@ -436,7 +438,7 @@
     <string name="permlab_manageFingerprint" msgid="5640858826254575638">"хурууны хээний програм хангамжийг удирдах"</string>
     <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Хурууны хээний загварыг нэмэх эсвэл усгтах үйлдлийг хийх зөвшөөрлийг програмд олгодог."</string>
     <string name="permlab_useFingerprint" msgid="3150478619915124905">"хурууны хээний програм хангамжийг ашиглах"</string>
-    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Баталгаажуулалт хийх зорилгоор хурууны хээний програм хамгамжийг ашиглах зөвшөөрлийг програмд олгодог"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Баталгаажуулалт хийх зорилгоор хурууны хээний апп хамгамжийг ашиглах зөвшөөрлийг аппд олгодог"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Хурууны хээг дутуу уншуулсан байна. Дахин оролдоно уу."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Хурууны хээ боловсруулж чадахгүй байна. Дахин оролдоно уу."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Хурууны хээ мэдрэгч бохирдсон байна. Та цэвэрлэсний дараагаар дахин оролдоно уу."</string>
@@ -1059,16 +1061,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>
@@ -1208,7 +1206,7 @@
     <string name="ext_media_status_formatting" msgid="1085079556538644861">"Хэлбэршүүлж байна..."</string>
     <string name="ext_media_status_missing" msgid="5638633895221670766">"Оруулаагүй байна"</string>
     <string name="activity_list_empty" msgid="1675388330786841066">"Таарах активити олдсонгүй."</string>
-    <string name="permlab_route_media_output" msgid="6243022988998972085">"медиа гаралтын маршрут"</string>
+    <string name="permlab_route_media_output" msgid="6243022988998972085">"медиа гаралтын чиглэл"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Аппликешн нь медиа гаралтыг бусад гадаад төхөөрөмжрүү чиглүүлэх боломжтой."</string>
     <string name="permlab_readInstallSessions" msgid="3713753067455750349">"Суулгах харилцан үйлдлийг унших"</string>
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Аппликешн-д суулгах сешн уншихыг зөвшөөрнө. Энэ нь идэвхтэй багцуудыг суулгалтын талаар дэлгэрэнгүй мэдээллийг үзэх боломж олгоно."</string>
@@ -1240,7 +1238,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">"VR сонсогч"</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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2 дахь ажил <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3 дахь ажил <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1679,8 +1679,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Таны хийсэн өөрчлөлтийг хадгалахгүй бөгөөд жишээ <xliff:g id="TIMEOUT">%1$s</xliff:g> секундын дотор дахин эхлэх болно..."</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Цуцлах"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Одоо шинэчлэх"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Энэ төхөөрөмжийг хязгаарлалтгүй ашиглахын тулд үйлдвэрийн тохиргоонд дахин тохируулна уу"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Дэлгэрэнгүй үзэх бол дарна уу."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 99465cc..bee5dd5 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"आपल्‍या हस्तक्षेपाशिवाय अ‍ॅपला कॉल करण्‍यासाठी IMS सेवा वापरण्याची अनुमती देते."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"फोन स्थिती आणि ओळख वाचा"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"डिव्हाइसच्या फोन वैशिष्ट्यांवर प्रवेश करण्यास अॅप ला अनुमती देते. ही परवानगी कॉल सक्रिय असला किंवा नसला तरीही, फोन नंबर आणि डिव्हाइस ID आणि कॉलद्वारे कनेक्ट केलेला रीमोट नंबर निर्धारित करण्यासाठी अॅप ला अनुमती देते."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"फोन नंबर वाचा"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"अॅपला डिव्हाइसच्या फोन नंबरमध्ये प्रवेश करण्याची अनुमती देते."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"टॅबलेट निष्क्रिय होण्यापासून प्रतिबंधित करा"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"निष्क्रिय होण्यापासून प्रतिबंध करा"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"फोन निष्‍क्रिय होण्‍यापासून प्रतिबंधित करा"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2 रे कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3 रे कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"आपण कोणतेही बदल गमवाल आणि डेमो पुन्हा <xliff:g id="TIMEOUT">%1$s</xliff:g> सेकंदांमध्ये प्रारंभ होईल..."</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"रद्द करा"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"आता रीसेट करा"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"हे डिव्हाइस निर्बंधांशिवाय वापरण्यासाठी फॅक्टरी रीसेट करा"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"अधिक जाणून घेण्यासाठी स्पर्श करा."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 1e7e281..5dcff04 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Membenarkan apl menggunakan perkhidmatan IMS untuk membuat panggilan tanpa campur tangan anda."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"baca status dan identiti telefon"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Membenarkan apl mengakses ciri telefon pada peranti. Kebenaran ini membolehkan apl menentukan nombor telefon dan ID peranti, sama ada panggilan aktif dan nombor jauh yang dihubungkan dengan panggilan."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"baca nombor telefon"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Membenarkan apl mengakses nombor telefon peranti."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"menghalang tablet daripada tidur"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"halang TV daripada tidur"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"halang telefon daripada tidur"</string>
@@ -1059,16 +1061,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Kelantangan media"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Kelantangan pemberitahuan"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Nada dering lalai"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Lalai (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Tiada"</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">"Bunyi penggera"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Bunyi pemberitahuan"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Tidak diketahui"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Rangkaian Wi-Fi tersedia</item>
       <item quantity="one">Rangkaian Wi-Fi tersedia</item>
@@ -1564,6 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> kerja ke-2"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> kerja ke-3"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Anda akan kehilangan sebarang perubahan yang dibuat dan tunjuk cara akan dimulakan sekali lagi dalam masa <xliff:g id="TIMEOUT">%1$s</xliff:g> saat…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Batal"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Tetapkan semula sekarang"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Lakukan tetapan semula kilang untuk menggunakan peranti ini tanpa sekatan"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Ketik untuk mengetahui lebih lanjut."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> dilumpuhkan"</string>
     <string name="conference_call" msgid="3751093130790472426">"Panggilan Sidang"</string>
+    <!-- no translation found for tooltip_popup_title (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 99d6423..086a2ef 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"သင့်ရဲ့ဝင်ရောက်စွက်ဖက်မှုမပါဘဲ IMS ဝန်ဆောင်မှုကိုအသုံးပြုပြီး ဖုန်းခေါ်ဆိုနိုင်ရန် အပ်ဖ်ကို ခွင့်ပြုထားပါ။"</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"ဖုန်းရဲ့ အခြေအနေ နှင့် အမှတ်သညာအား ဖတ်ခြင်း"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"အပလီကေးရှင်းအား ဖုန်းရဲ့ စွမ်းဆောင်ချက်များအား သုံးခွင့်ပြုပါ။ အပလီကေးရှင်းအနေဖြင့် ဖုန်းနံပါတ်၊ စက်နံပါတ်၊ ဖုန်းခေါ်နေမှု ရှိမရှိနှင့် တဖက်မှ ဖုန်းနံပါတ် များအား သိရှိနိုင်ပါသည်"</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ဖုန်းနံပါတ်ကို ဖတ်ရန်"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"စက်ပစ္စည်း၏ ဖုန်းနံပါတ်အား အက်ပ်ကို အသုံးပြုခွင့်ပေးပါ။"</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"တက်ပလက်အား ပိတ်ခြင်းမှ ကာကွယ်ခြင်း"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"တီဗွီအား နားနေခြင်းမှ ကာကွယ်ရန်"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ဖုန်းအနားယူခြင်းမပြုလုပ်စေရန်"</string>
@@ -643,7 +645,7 @@
     <string name="relationTypeAssistant" msgid="6274334825195379076">"အထောက်အကူ"</string>
     <string name="relationTypeBrother" msgid="8757913506784067713">"ညီအကို"</string>
     <string name="relationTypeChild" msgid="1890746277276881626">"သားသမီး"</string>
-    <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"အတူနေအပေါင်းအဖော်"</string>
+    <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"အတူနေအဖော်"</string>
     <string name="relationTypeFather" msgid="5228034687082050725">"ဖခင်"</string>
     <string name="relationTypeFriend" msgid="7313106762483391262">"သူငယ်ချင်း"</string>
     <string name="relationTypeManager" msgid="6365677861610137895">"မန်နေဂျာ"</string>
@@ -651,7 +653,7 @@
     <string name="relationTypeParent" msgid="4755635567562925226">"မိဘ"</string>
     <string name="relationTypePartner" msgid="7266490285120262781">"လုပ်ဖော်ကိုင်ဖက်"</string>
     <string name="relationTypeReferredBy" msgid="101573059844135524">"မှရည်ညွှန်းပေးသည်"</string>
-    <string name="relationTypeRelative" msgid="1799819930085610271">"ဆွေးမျိုး"</string>
+    <string name="relationTypeRelative" msgid="1799819930085610271">"ဆွေမျိုး"</string>
     <string name="relationTypeSister" msgid="1735983554479076481">"ညီအမ"</string>
     <string name="relationTypeSpouse" msgid="394136939428698117">"အိမ်ထောင်ဖက်"</string>
     <string name="sipAddressTypeCustom" msgid="2473580593111590945">"မိမိစိတ်ကြိုက်"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"ဒုတိယအလုပ် <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"တတိယအလုပ် <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"ပြောင်းလဲမှုများကို ဆုံးရှုံးသွားမည်ဖြစ်ပြီး သရုပ်ပြချက်သည် <xliff:g id="TIMEOUT">%1$s</xliff:g> စက္ကန့်အတွင်း ပြန်လည်စတင်ပါမည်…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"မလုပ်တော့"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"ယခုပြန်လည်သတ်မှတ်ပါ"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"ဤစက်ပစ္စည်းကို ကန့်သတ်ချက်များမပါဘဲ အသုံးပြုရန် စက်ရုံထုတ်ဆက်တင်အတိုင်း ပြန်လည်သတ်မှတ်ပါ"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"ပိုမိုလေ့လာရန် တို့ပါ။"</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 324f0d7..cc3232a 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Lar appen bruke nettprattjenesten til å ringe uten at du gjør noe."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"lese telefonstatus og -identitet"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Lar appen bruke enhetens telefonfunksjoner. Med denne tillatelsen kan appen finne telefonnummer og enhets-ID-er, registrere om en samtale pågår, og se det eksterne nummeret det opprettes en forbindelse med via oppringing."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"les telefonnummeret"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Gir appen tilgang til telefonnummeret til enheten."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"hindre nettbrettet fra å gå over til sovemodus"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"hindre TV-en i å gå i hvilemodus"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"forhindre telefonen fra å sove"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Andre jobbrelaterte <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Tredje jobbrelaterte <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Du mister eventuelle endringer, og demoen starter på nytt om <xliff:g id="TIMEOUT">%1$s</xliff:g> sekunder."</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Avbryt"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Tilbakestill nå"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Tilbakestill til fabrikkstandard for å bruke denne enheten uten begrensninger"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Trykk for å finne ut mer."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index caf3688..1517b08 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"तपाईँको हस्तक्षेप बिना नै कल गर्न IMS सेवा प्रयोग गर्न अनुप्रयोगलाई अनुमति दिन्छ।"</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"फोन स्थिति र पहिचान पढ्नुहोस्"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"उपकरणको फोन विशेषताहरूको पहुँच गर्न अनुप्रयोगलाई अनुमति दिन्छ। यस अनुमतिले फोन नम्बर र उपकरणको IDs, कल सक्षम छ कि छैन र कलद्वारा जोडिएको टाढाको नम्बर निर्धारण गर्न अनुमति दिन्छ।"</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"फोन नम्बर पढ्ने"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"यस अनुप्रयोगलाई यस यन्त्रको फोन नम्बरमाथि पहुँच राख्न दिनुहोस्।"</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ट्याब्लेटलाई निन्द्रामा जानबाट रोक्नुहोस्"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"TV निभ्नबाट जोगाउनुहोस्"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"फोनलाई निदाउनबाट रोक्नुहोस्"</string>
@@ -553,30 +555,30 @@
     <item msgid="1735177144948329370">"घरको फ्याक्स"</item>
     <item msgid="603878674477207394">"पेजर"</item>
     <item msgid="1650824275177931637">"अन्य"</item>
-    <item msgid="9192514806975898961">"अनुकूलन"</item>
+    <item msgid="9192514806975898961">"आफू अनुकूल"</item>
   </string-array>
   <string-array name="emailAddressTypes">
     <item msgid="8073994352956129127">"गृह"</item>
     <item msgid="7084237356602625604">"काम"</item>
     <item msgid="1112044410659011023">"अन्य"</item>
-    <item msgid="2374913952870110618">"अनुकूलन"</item>
+    <item msgid="2374913952870110618">"आफू अनुकूल"</item>
   </string-array>
   <string-array name="postalAddressTypes">
     <item msgid="6880257626740047286">"गृह"</item>
     <item msgid="5629153956045109251">"काम"</item>
     <item msgid="4966604264500343469">"अन्य"</item>
-    <item msgid="4932682847595299369">"अनुकूलन"</item>
+    <item msgid="4932682847595299369">"आफू अनुकूल"</item>
   </string-array>
   <string-array name="imAddressTypes">
     <item msgid="1738585194601476694">"गृह"</item>
     <item msgid="1359644565647383708">"काम"</item>
     <item msgid="7868549401053615677">"अन्य"</item>
-    <item msgid="3145118944639869809">"अनुकूलन"</item>
+    <item msgid="3145118944639869809">"आफू अनुकूल"</item>
   </string-array>
   <string-array name="organizationTypes">
     <item msgid="7546335612189115615">"काम गर्नुहोस्"</item>
     <item msgid="4378074129049520373">"अन्य"</item>
-    <item msgid="3455047468583965104">"अनुकूलन"</item>
+    <item msgid="3455047468583965104">"आफू अनुकूल"</item>
   </string-array>
   <string-array name="imProtocols">
     <item msgid="8595261363518459565">"AIM"</item>
@@ -588,7 +590,7 @@
     <item msgid="2506857312718630823">"ICQ"</item>
     <item msgid="1648797903785279353">"Jabber"</item>
   </string-array>
-    <string name="phoneTypeCustom" msgid="1644738059053355820">"अनुकूलन"</string>
+    <string name="phoneTypeCustom" msgid="1644738059053355820">"आफू अनुकूल"</string>
     <string name="phoneTypeHome" msgid="2570923463033985887">"गृह"</string>
     <string name="phoneTypeMobile" msgid="6501463557754751037">"मोबाइल"</string>
     <string name="phoneTypeWork" msgid="8863939667059911633">"काम"</string>
@@ -609,24 +611,24 @@
     <string name="phoneTypeWorkPager" msgid="649938731231157056">"कार्य पेजर"</string>
     <string name="phoneTypeAssistant" msgid="5596772636128562884">"सहायक"</string>
     <string name="phoneTypeMms" msgid="7254492275502768992">"MMS"</string>
-    <string name="eventTypeCustom" msgid="7837586198458073404">"अनुकूलन"</string>
+    <string name="eventTypeCustom" msgid="7837586198458073404">"आफू अनुकूल"</string>
     <string name="eventTypeBirthday" msgid="2813379844211390740">"जन्मदिन"</string>
     <string name="eventTypeAnniversary" msgid="3876779744518284000">"वार्षिक समारोह"</string>
     <string name="eventTypeOther" msgid="7388178939010143077">"अन्य"</string>
-    <string name="emailTypeCustom" msgid="8525960257804213846">"अनुकूलन"</string>
+    <string name="emailTypeCustom" msgid="8525960257804213846">"आफू अनुकूल"</string>
     <string name="emailTypeHome" msgid="449227236140433919">"गृह"</string>
     <string name="emailTypeWork" msgid="3548058059601149973">"काम"</string>
     <string name="emailTypeOther" msgid="2923008695272639549">"अन्य"</string>
     <string name="emailTypeMobile" msgid="119919005321166205">"मोबाइल"</string>
-    <string name="postalTypeCustom" msgid="8903206903060479902">"अनुकूलन"</string>
+    <string name="postalTypeCustom" msgid="8903206903060479902">"आफू अनुकूल"</string>
     <string name="postalTypeHome" msgid="8165756977184483097">"गृह"</string>
     <string name="postalTypeWork" msgid="5268172772387694495">"काम"</string>
     <string name="postalTypeOther" msgid="2726111966623584341">"अन्य"</string>
-    <string name="imTypeCustom" msgid="2074028755527826046">"अनुकूलन"</string>
+    <string name="imTypeCustom" msgid="2074028755527826046">"आफू अनुकूल"</string>
     <string name="imTypeHome" msgid="6241181032954263892">"गृह"</string>
     <string name="imTypeWork" msgid="1371489290242433090">"काम"</string>
     <string name="imTypeOther" msgid="5377007495735915478">"अन्य"</string>
-    <string name="imProtocolCustom" msgid="6919453836618749992">"अनुकूलन"</string>
+    <string name="imProtocolCustom" msgid="6919453836618749992">"आफू अनुकूल"</string>
     <string name="imProtocolAim" msgid="7050360612368383417">"AIM"</string>
     <string name="imProtocolMsn" msgid="144556545420769442">"Windows Live"</string>
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
@@ -638,8 +640,8 @@
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
     <string name="orgTypeWork" msgid="29268870505363872">"काम"</string>
     <string name="orgTypeOther" msgid="3951781131570124082">"अन्य"</string>
-    <string name="orgTypeCustom" msgid="225523415372088322">"अनुकूलन"</string>
-    <string name="relationTypeCustom" msgid="3542403679827297300">"अनुकूलन"</string>
+    <string name="orgTypeCustom" msgid="225523415372088322">"आफू अनुकूल"</string>
+    <string name="relationTypeCustom" msgid="3542403679827297300">"आफू अनुकूल"</string>
     <string name="relationTypeAssistant" msgid="6274334825195379076">"सहायक"</string>
     <string name="relationTypeBrother" msgid="8757913506784067713">"भाइ"</string>
     <string name="relationTypeChild" msgid="1890746277276881626">"सन्तान"</string>
@@ -653,8 +655,8 @@
     <string name="relationTypeReferredBy" msgid="101573059844135524">"द्वारा उल्लिखित"</string>
     <string name="relationTypeRelative" msgid="1799819930085610271">"आफन्त"</string>
     <string name="relationTypeSister" msgid="1735983554479076481">"बहिनी"</string>
-    <string name="relationTypeSpouse" msgid="394136939428698117">"पति-पत्नि"</string>
-    <string name="sipAddressTypeCustom" msgid="2473580593111590945">"अनुकूलन"</string>
+    <string name="relationTypeSpouse" msgid="394136939428698117">"पति-पत्नी"</string>
+    <string name="sipAddressTypeCustom" msgid="2473580593111590945">"आफू अनुकूल"</string>
     <string name="sipAddressTypeHome" msgid="6093598181069359295">"गृह"</string>
     <string name="sipAddressTypeWork" msgid="6920725730797099047">"काम गर्नुहोस्"</string>
     <string name="sipAddressTypeOther" msgid="4408436162950119849">"अन्य"</string>
@@ -1029,7 +1031,7 @@
     <string name="smv_process" msgid="5120397012047462446">"प्रक्रिया <xliff:g id="PROCESS">%1$s</xliff:g> यसको आफ्नै कडामोड नीतिका कारण उल्लङ्घन गरिएको छ।"</string>
     <string name="android_upgrading_title" msgid="1584192285441405746">"एन्ड्रोइड अपग्रेड हुँदैछ…"</string>
     <string name="android_start_title" msgid="8418054686415318207">"Android शुरू हुँदैछ..."</string>
-    <string name="android_upgrading_fstrim" msgid="8036718871534640010">"भण्डारण अनुकूलन गर्दै।"</string>
+    <string name="android_upgrading_fstrim" msgid="8036718871534640010">"भण्डारण आफू अनुकूल गर्दै।"</string>
     <string name="android_upgrading_notification_title" msgid="8428357096969413169">"Android को अद्यावधिकलाई सम्पन्न गर्दै…"</string>
     <string name="android_upgrading_notification_body" msgid="5761201379457064286">"स्तरवृद्धि सम्पन्न नभएसम्म केही अनुप्रयोगहरू राम्ररी काम नगर्न सक्छन्"</string>
     <string name="app_upgrading_toast" msgid="3008139776215597053">"<xliff:g id="APPLICATION">%1$s</xliff:g> को स्तरवृद्धि हुँदैछ…"</string>
@@ -1065,16 +1067,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>
@@ -1106,8 +1104,8 @@
     <string name="wifi_connect_alert_message" msgid="6451273376815958922">"अनुप्रयोग %1$s Wifi सञ्जाल %2$s मा जडान गर्न चाहन्छ"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"एउटा अनुप्रयोग"</string>
     <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_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_message" msgid="8064677407830620023">"सेटिङहरूका लागि ट्याप गर्नुहोस्"</string>
     <string name="accept" msgid="1645267259272829559">"स्वीकार्नुहोस्"</string>
@@ -1570,6 +1568,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"कार्यालयको दोस्रो <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"कार्यालयको तेस्रो <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1687,8 +1687,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"तपाईँ सबै परिवर्तनहरू गुमाउनु हुनेछ र <xliff:g id="TIMEOUT">%1$s</xliff:g> सेकेन्डमा डेमो फेरि सुरु हुनेछ…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"रद्द गर्नुहोस्"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"अहिले रिसेट गर्नुहोस्"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"यस यन्त्रलाई सीमितताहरू बिना प्रयोग गर्नका लागि फ्याक्ट्री रिसेट गर्नुहोस्"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"थप जान्नका लागि छुनुहोस्।"</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 0848304..652021d 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Hiermee kan de app de IMS-service gebruiken om te bellen zonder je tussenkomst."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"telefoonstatus en -identiteit lezen"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Hiermee kan de app toegang krijgen tot de telefoonfuncties van het apparaat, Met deze toestemming kan de app het telefoonnummer en de apparaat-ID\'s bepalen, of een oproep actief is, en het andere telefoonnummer waarmee wordt gebeld."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"telefoonnummer lezen"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Hiermee kan de app toegang krijgen tot het telefoonnummer van het apparaat."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"voorkomen dat tablet overschakelt naar slaapmodus"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"voorkomen dat tv overschakelt naar slaapmodus"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"voorkomen dat telefoon overschakelt naar slaapmodus"</string>
@@ -1059,16 +1061,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>
@@ -1530,8 +1528,8 @@
     <string name="mediasize_japanese_kahu" msgid="6872696027560065173">"Kahu"</string>
     <string name="mediasize_japanese_kaku2" msgid="2359077233775455405">"Kaku2"</string>
     <string name="mediasize_japanese_you4" msgid="2091777168747058008">"You4"</string>
-    <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"Onbekend portret"</string>
-    <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"Onbekend landschap"</string>
+    <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"Onbekend staand"</string>
+    <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"Onbekend liggend"</string>
     <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Geannuleerd"</string>
     <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Fout bij schrijven van content"</string>
     <string name="reason_unknown" msgid="6048913880184628119">"onbekend"</string>
@@ -1564,6 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2e <xliff:g id="LABEL">%1$s</xliff:g>, werk"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3e <xliff:g id="LABEL">%1$s</xliff:g>, werk"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Je wijzigingen gaan verloren. De demo wordt opnieuw gestart over <xliff:g id="TIMEOUT">%1$s</xliff:g> seconden…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Annuleren"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Nu resetten"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Zet dit apparaat terug op de fabrieksinstellingen om het zonder beperkingen te gebruiken"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Tik voor meer informatie."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
index 3e886bc..4e95358b 100644
--- a/core/res/res/values-pa-rIN/strings.xml
+++ b/core/res/res/values-pa-rIN/strings.xml
@@ -40,7 +40,7 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> ਸਕਿੰਟ"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> ਸਕਿੰਟ"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;ਬਿਨਾਂ ਸਿਰਲੇਖ&gt;"</string>
-    <string name="emptyPhoneNumber" msgid="7694063042079676517">"(ਕੋਈ ਫੋਨ ਨੰਬਰ ਨਹੀਂ)"</string>
+    <string name="emptyPhoneNumber" msgid="7694063042079676517">"(ਕੋਈ ਫ਼ੋਨ ਨੰਬਰ ਨਹੀਂ)"</string>
     <string name="unknownName" msgid="6867811765370350269">"ਅਗਿਆਤ"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"ਵੌਇਸਮੇਲ"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
@@ -252,7 +252,7 @@
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
     <string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS ਸੁਨੇਹੇ ਭੇਜਣ ਅਤੇ ਦੇਖਣ"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"ਸਟੋਰੇਜ"</string>
-    <string name="permgroupdesc_storage" msgid="637758554581589203">"ਆਪਣੀ ਡੀਵਾਈਸ ’ਤੇ ਫੋਟੋਆਂ, ਮੀਡੀਆ ਅਤੇ ਫਾਈਲਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ"</string>
+    <string name="permgroupdesc_storage" msgid="637758554581589203">"ਆਪਣੀ ਡੀਵਾਈਸ ’ਤੇ ਫ਼ੋਟੋਆਂ, ਮੀਡੀਆ ਅਤੇ ਫਾਈਲਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"ਮਾਈਕ੍ਰੋਫੋਨ"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ਔਡੀਓ ਰਿਕਾਰਡ ਕਰਨ"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"ਕੈਮਰਾ"</string>
@@ -376,7 +376,9 @@
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ਕਾਲ ਸੇਵਾ ਤੱਕ ਪਹੁੰਚ"</string>
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਦਖ਼ਲ ਤੋਂ ਬਿਨਾਂ ਕਾਲਾਂ ਕਰਨ ਲਈ IMS ਸੇਵਾ ਵਰਤਣ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ।"</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"ਫੋਨ ਸਥਿਤੀ ਅਤੇ ਪਛਾਣ ਪੜ੍ਹੋ"</string>
-    <string name="permdesc_readPhoneState" msgid="1639212771826125528">"ਐਪ ਨੂੰ ਡੀਵਾਈਸ ਦੀਆਂ ਫੋਨ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਤੱਕ ਪਹੁੰਚ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਅਨੁਮਤੀ ਐਪ ਨੂੰ ਫੋਨ ਨੰਬਰ ਅਤੇ ਡੀਵਾਈਸ ID ਨਿਰਧਾਰਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ, ਇੱਕ ਕਾਲ ਸਕਿਰਿਆ ਹੈ ਜਾਂ ਨਹੀਂ ਅਤੇ ਰਿਮੋਟ ਨੰਬਰ ਇੱਕ ਕਾਲ ਨਾਲ ਕਨੈਕਟ ਹੈ ਜਾਂ ਨਹੀਂ।"</string>
+    <string name="permdesc_readPhoneState" msgid="1639212771826125528">"ਐਪ ਨੂੰ ਡੀਵਾਈਸ ਦੀਆਂ ਫੋਨ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਤੱਕ ਪਹੁੰਚ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਅਨੁਮਤੀ ਐਪ ਨੂੰ ਫ਼ੋਨ ਨੰਬਰ ਅਤੇ ਡੀਵਾਈਸ ID ਨਿਰਧਾਰਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ, ਇੱਕ ਕਾਲ ਸਕਿਰਿਆ ਹੈ ਜਾਂ ਨਹੀਂ ਅਤੇ ਰਿਮੋਟ ਨੰਬਰ ਇੱਕ ਕਾਲ ਨਾਲ ਕਨੈਕਟ ਹੈ ਜਾਂ ਨਹੀਂ।"</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ਫ਼ੋਨ ਨੰਬਰ ਪੜ੍ਹੋ"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"ਡੀਵਾਈਸ ਦੇ ਫ਼ੋਨ ਨੰਬਰ \'ਤੇ ਪਹੁੰਚ ਕਰਨ ਲਈ ਐਪ ਨੂੰ ਇਜਾਜ਼ਤ ਦਿੰਦਾ ਹੈ।"</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ਟੈਬਲੇਟ ਨੂੰ ਸਲੀਪਿੰਗ ਤੋਂ ਰੋਕੋ"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"TV ਨੂੰ ਸਲੀਪਿੰਗ ਤੋਂ ਰੋਕੋ"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ਫੋਨ ਨੂੰ ਸਲੀਪਿੰਗ ਤੋਂ ਰੋਕੋ"</string>
@@ -549,7 +551,7 @@
     <item msgid="8901098336658710359">"ਘਰ"</item>
     <item msgid="869923650527136615">"ਮੋਬਾਈਲ"</item>
     <item msgid="7897544654242874543">"ਕੰਮ"</item>
-    <item msgid="1103601433382158155">"ਦਫ਼ਤਰ ਦੀ ਫੈਕਸ"</item>
+    <item msgid="1103601433382158155">"ਕਾਰਜ-ਸਥਾਨ ਫੈਕਸ"</item>
     <item msgid="1735177144948329370">"ਘਰ ਦੀ ਫੈਕਸ"</item>
     <item msgid="603878674477207394">"ਪੇਜਰ"</item>
     <item msgid="1650824275177931637">"ਹੋਰ"</item>
@@ -592,7 +594,7 @@
     <string name="phoneTypeHome" msgid="2570923463033985887">"ਘਰ"</string>
     <string name="phoneTypeMobile" msgid="6501463557754751037">"ਮੋਬਾਈਲ"</string>
     <string name="phoneTypeWork" msgid="8863939667059911633">"ਕੰਮ"</string>
-    <string name="phoneTypeFaxWork" msgid="3517792160008890912">"ਦਫ਼ਤਰ ਦੀ ਫੈਕਸ"</string>
+    <string name="phoneTypeFaxWork" msgid="3517792160008890912">"ਕਾਰਜ-ਸਥਾਨ ਫੈਕਸ"</string>
     <string name="phoneTypeFaxHome" msgid="2067265972322971467">"ਘਰ ਦੀ ਫੈਕਸ"</string>
     <string name="phoneTypePager" msgid="7582359955394921732">"ਪੇਜਰ"</string>
     <string name="phoneTypeOther" msgid="1544425847868765990">"ਹੋਰ"</string>
@@ -1059,16 +1061,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>
@@ -1152,7 +1150,7 @@
     <string name="usb_charging_notification_title" msgid="6895185153353640787">"ਇਹ ਡੀਵਾਈਸ USB ਰਾਹੀਂ ਚਾਰਜ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ"</string>
     <string name="usb_supplying_notification_title" msgid="5310642257296510271">"ਨੱਥੀ ਕੀਤੀ ਡੀਵਾਈਸ ਨੂੰ USB ਰਾਹੀਂ ਪਾਵਰ ਮਿਲ ਰਹੀ ਹੈ"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"ਫ਼ਾਈਲ ਟ੍ਰਾਂਸਫ਼ਰ ਲਈ USB"</string>
-    <string name="usb_ptp_notification_title" msgid="1347328437083192112">"ਫੋਟੋ ਟ੍ਰਾਂਸਫ਼ਰ ਲਈ USB"</string>
+    <string name="usb_ptp_notification_title" msgid="1347328437083192112">"ਫ਼ੋਟੋ ਟ੍ਰਾਂਸਫ਼ਰ ਲਈ USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI ਲਈ USB"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"ਇੱਕ USB ਐਕਸੈਸਰੀ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਟੈਪ ਕਰੋ।"</string>
@@ -1174,7 +1172,7 @@
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> ਤਿਆਰ ਹੋ ਰਿਹਾ ਹੈ"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ਤਰੁੱਟੀਆਂ ਦੀ ਜਾਂਚ ਕਰ ਰਿਹਾ ਹੈ"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"ਨਵੇਂ <xliff:g id="NAME">%s</xliff:g> ਦਾ ਪਤਾ ਲਗਾਇਆ ਗਿਆ"</string>
-    <string name="ext_media_ready_notification_message" msgid="4083398150380114462">"ਫੋਟੋਆਂ ਅਤੇ ਮੀਡੀਆ ਨੂੰ ਟ੍ਰਾਂਸਫ਼ਰ ਕਰਨ ਲਈ"</string>
+    <string name="ext_media_ready_notification_message" msgid="4083398150380114462">"ਫ਼ੋਟੋਆਂ ਅਤੇ ਮੀਡੀਆ ਨੂੰ ਟ੍ਰਾਂਸਫ਼ਰ ਕਰਨ ਲਈ"</string>
     <string name="ext_media_unmountable_notification_title" msgid="8295123366236989588">"ਕਰਪਟਿਡ <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_unmountable_notification_message" msgid="2343202057122495773">"<xliff:g id="NAME">%s</xliff:g> ਗ਼ਲਤ ਹੈ। ਠੀਕ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <string name="ext_media_unsupported_notification_title" msgid="3797642322958803257">"ਅਸਮਰਥਿਤ <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1564,6 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"ਦੂਸਰੀ ਕਾਰਜ-ਸਥਾਨ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"ਤੀਸਰੀ ਕਾਰਜ-ਸਥਾਨ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"ਤੁਸੀਂ ਕਿਸੇ ਵੀ ਤਬਦੀਲੀਆਂ ਨੂੰ ਗੁਆ ਬੈਠੋਂਗੇ ਅਤੇ ਡੈਮੋ <xliff:g id="TIMEOUT">%1$s</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਚਾਲੂ ਕੀਤਾ ਜਾਵੇਗਾ…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"ਰੱਦ ਕਰੋ"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"ਹੁਣੇ ਮੁੜ-ਸੈੱਟ ਕਰੋ"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"ਇਸ ਡੀਵਾਈਸ ਨੂੰ ਬਿਨਾਂ ਪਾਬੰਦੀਆਂ ਦੇ ਵਰਤਣ ਲਈ ਫੈਕਟਰੀ ਰੀਸੈੱਟ ਕਰੋ"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"ਹੋਰ ਜਾਣਨ ਲਈ ਸਪਰਸ਼ ਕਰੋ।"</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 92a2e2a..3217af5 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -383,6 +383,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Zezwala aplikacji na korzystanie z usługi komunikatora, by nawiązywać połączenia bez Twojego udziału."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"odczytywanie stanu i informacji o telefonie"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Pozwala aplikacji na dostęp do funkcji telefonicznych urządzenia. Aplikacja z tym uprawnieniem może odczytać numer telefonu i identyfikator urządzenia, sprawdzić, czy połączenie jest aktywne, oraz poznać numer, z którym jest nawiązane połączenie."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"odczyt numeru telefonu"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Zezwala aplikacji na dostęp do numeru telefonu urządzenia."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"zapobieganie przechodzeniu tabletu do trybu uśpienia"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"powstrzymywanie usypiania telewizora"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"zapobieganie przejściu telefonu w stan uśpienia"</string>
@@ -1105,16 +1107,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 +1616,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> – praca 2"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> – praca 3"</string>
     <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>
@@ -1753,8 +1753,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Stracisz wszystkie wprowadzone zmiany, a tryb demo uruchomi się ponownie za <xliff:g id="TIMEOUT">%1$s</xliff:g> s…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Anuluj"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Resetuj teraz"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Aby używać tego urządzenia bez ograniczeń, przywróć ustawienia fabryczne"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Kliknij, by dowiedzieć się więcej."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index bf9e15d..9631684 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permite que o app use o serviço de mensagens instantâneas para fazer chamadas sem sua intervenção."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"ler status e identidade do telefone"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite que o app acesse os recursos de telefonia do dispositivo. Esta permissão autoriza o app a determinar o número de telefone e IDs de dispositivo, quando uma chamada está ativa, e o número remoto conectado a uma chamada."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ler número de telefone"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Permite que o app acesse o número de telefone do dispositivo."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"impedir modo de inatividade do tablet"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"impedir a suspensão da TV"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir modo de inatividade do telefone"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Segundo <xliff:g id="LABEL">%1$s</xliff:g> de trabalho"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Terceiro <xliff:g id="LABEL">%1$s</xliff:g> de trabalho"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Você perderá todas as alterações. A demonstração será iniciada novamente em <xliff:g id="TIMEOUT">%1$s</xliff:g> segundos…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Cancelar"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Reiniciar agora"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Redefinir para a configuração original para usar este dispositivo sem restrições"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toque para saber mais."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index e09daa5..4c07dfa7 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permite que a aplicação utilize o serviço IMS para fazer chamadas sem a sua intervenção."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"ler o estado e a identidade do telemóvel"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite que a aplicação aceda às funcionalidades de telefone do dispositivo. Esta autorização permite que a aplicação determine o número de telefone e IDs do dispositivo, se alguma chamada está ativa e qual o número remoto ligado por uma chamada."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ler o número de telefone"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Permite que a aplicação aceda ao número de telefone do dispositivo."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"impedir que o tablet entre em inactividade"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"impedir a TV de entrar no modo de suspensão"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir modo de inactividade do telefone"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2.º <xliff:g id="LABEL">%1$s</xliff:g> de trabalho"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3.º <xliff:g id="LABEL">%1$s</xliff:g> de trabalho"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Perderá todas as alterações e a demonstração começará novamente dentro de <xliff:g id="TIMEOUT">%1$s</xliff:g> segundos…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Cancelar"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Repor agora"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Repor os dados de fábrica para utilizar o dispositivo sem restrições"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toque para saber mais."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index bf9e15d..9631684 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permite que o app use o serviço de mensagens instantâneas para fazer chamadas sem sua intervenção."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"ler status e identidade do telefone"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite que o app acesse os recursos de telefonia do dispositivo. Esta permissão autoriza o app a determinar o número de telefone e IDs de dispositivo, quando uma chamada está ativa, e o número remoto conectado a uma chamada."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ler número de telefone"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Permite que o app acesse o número de telefone do dispositivo."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"impedir modo de inatividade do tablet"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"impedir a suspensão da TV"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir modo de inatividade do telefone"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Segundo <xliff:g id="LABEL">%1$s</xliff:g> de trabalho"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Terceiro <xliff:g id="LABEL">%1$s</xliff:g> de trabalho"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Você perderá todas as alterações. A demonstração será iniciada novamente em <xliff:g id="TIMEOUT">%1$s</xliff:g> segundos…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Cancelar"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Reiniciar agora"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Redefinir para a configuração original para usar este dispositivo sem restrições"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toque para saber mais."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 7f96d2e..c1f1d7b 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -380,6 +380,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permite aplicației să folosească serviciul IMS pentru apeluri, fără intervenția dvs."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"citește starea și identitatea telefonului"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite aplicației să acceseze funcțiile de telefon ale dispozitivului. Cu această permisiune aplicația stabilește numărul de telefon și ID-urile de dispozitiv, dacă un apel este activ, precum și numărul de la distanță conectat printr-un apel."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"să citească numărul de telefon"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Permite aplicației să acceseze numărul de telefon al dispozitivului."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"împiedicarea computerului tablet PC să intre în repaus"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"împiedică intrarea televizorului în stare de inactivitate"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"împiedicare intrare telefon în repaus"</string>
@@ -1082,16 +1084,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Volumul media"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volum notificare"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Ton de apel prestabilit"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Prestabilit (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Niciunul"</string>
-    <string name="ringtone_picker_title" msgid="3515143939175119094">"Tonuri de sonerie"</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" msgid="3515143939175119094">"Tonuri de apel"</string>
+    <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sunete de alarmă"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sunete pentru notificare"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Necunoscut"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="few">Rețele Wi-Fi disponibile</item>
       <item quantity="other">Rețele Wi-Fi disponibile</item>
@@ -1591,6 +1589,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> pentru serviciu (2)"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> pentru serviciu (3)"</string>
     <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>
@@ -1717,8 +1717,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Veți pierde toate modificările, iar demonstrația va începe din nou peste <xliff:g id="TIMEOUT">%1$s</xliff:g> secunde…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Anulați"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Resetați acum"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Reveniți la setările din fabrică pentru a folosi acest dispozitiv fără restricții"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Atingeți pentru a afla mai multe."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> a fost dezactivat"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conferință telefonică"</string>
+    <!-- no translation found for tooltip_popup_title (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 9e25bb7..0d51926 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -383,6 +383,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Позволяет приложению совершать звонки с помощью службы IMS без вашего вмешательства."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"Получение данных о статусе телефона"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Приложение получит доступ к функциям телефона на устройстве. Кроме того, оно сможет определять номера телефонов и серийные номера моделей, состояние активности вызова, а также удаленные номера, с которыми установлено соединение."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"Чтение номера телефона"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Приложение получит доступ к телефонному номеру устройства."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"Отключение спящего режима"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"запрещать переход в спящий режим"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"Отключение спящего режима"</string>
@@ -1105,16 +1107,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 +1616,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Задача 2: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Задача 3: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1753,8 +1753,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Все изменения будут утеряны. Деморежим будет перезапущен через <xliff:g id="TIMEOUT">%1$s</xliff:g> сек."</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Отмена"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Сбросить"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Сброс до заводских настроек для работы без ограничений"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Нажмите, чтобы узнать больше."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index b106464..ecf6eaf 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>
@@ -284,7 +284,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"කෙටිමං අස්ථාපනය කරන්න"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"පරිශීලක මැදිහත්වීමෙන් තොරව මුල්තිර කෙටිමං එක් කිරීමට යෙදුමකට අවසර දෙයි."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"පිටවන ඇමතුම් වල මග වෙනස් කිරීම"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"ඇමතුම වෙනත් අංකයකට හරවා යැවීම හෝ ඇමතුම මුළුමනින්ම නැවත් වීම වැනි විකල්ප සමඟ පිටතට යන ඇමතුමකදී ඩයල් කළ අංකය බැලීමට යෙදුමට ඉඩ දෙන්න."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"ඇමතුම වෙනත් අංකයකට හරවා යැවීම හෝ ඇමතුම මුළුමනින්ම නැවත්වීම වැනි විකල්ප සමඟ පිටතට යන ඇමතුමකදී අංකනය කළ අංකය බැලීමට යෙදුමට ඉඩ දෙයි."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"කෙටි පණිවිඩ ලබාගැනීම (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"SMS පණිවිඩ ලැබීමට සහ ක්‍රියාත්මක කිරීමට යෙදුමට අවසර දෙන්න. මෙහි තේරුම යෙදුමට ඔබගේ උපාංගයට ලැබෙන පණිවිඩ අධීක්ෂණය කිරීමට හැකිවීම වන අතර, ඒවා ඔබට නොපෙන්වා මකා දැමීමටද හැකි වීමයි."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"පෙළ පණිවුඩ ලබාගන්න (MMS)"</string>
@@ -376,7 +376,9 @@
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ඇමතුම් සේවාවට පිවිසෙන්න"</string>
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"ඔබේ මැදිහත්වීමකින් තොරව ඇමතුම් සිදු කිරීමට  IMS සේවාව භාවිතයට යෙදුමට ඉඩ දෙන්න."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"දුරකථනයේ තත්වය සහ අනන්‍යතාවය කියවීම"</string>
-    <string name="permdesc_readPhoneState" msgid="1639212771826125528">"උපාංගයේ දුරකථන විශේෂාංග වෙත පිවිසීමට යෙදුමට අවසර දෙන්න. ඇමතුම සක්‍රිය වුවත් සහ ඇමතුමකින් දුරස්ථ අංකය සම්බන්ධ වුවත් දුරකථන අංකය සහ උපාංග ID හඳුනා ගැනීමට මෙම අවසරය යෙදුමට අවසර දෙයි."</string>
+    <string name="permdesc_readPhoneState" msgid="1639212771826125528">"උපාංගයේ දුරකථන විශේෂාංග වෙත ප්‍රවේශයට යෙදුමට ඉඩ දෙයි.  ඇමතුම සක්‍රිය වුවත්, සහ ඇමතුමකින් දුරස්ථ අංකය සම්බන්ධ වුවත් දුරකථන අංකය සහ උපාංග ID හඳුනා ගැනීමට මෙම අවසරය යෙදුමට ඉඩ දෙයි."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"දුරකථන අංකය කියවන්න"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"උපාංගයේ දුරකථන අංකය වෙත පිවිසීමට යෙදුමට ඉඩ දෙන්න."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ටැබ්ලටය නින්දෙන් වැළක්වීම"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"රූපවාහිනිය නින්දට යාමෙන් නවත්වන්න"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"දුරකථනය නින්දට යාමෙන් වළකන්න"</string>
@@ -975,7 +977,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>
@@ -1061,16 +1063,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>
@@ -1104,7 +1102,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 +1334,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 +1380,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 +1564,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2වන වැඩ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3වන වැඩ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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 +1614,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>
@@ -1683,8 +1683,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"ඔබට යම් වෙනස් කිරීම් අහිමි වනු ඇති අතර ආදර්ශනය තත්පර <xliff:g id="TIMEOUT">%1$s</xliff:g>කින් නැවත ආරම්භ වනු ඇත…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"අවලංගු කරන්න"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"දැන් යළි සකසන්න"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"සීමා කිරීම්වලින් තොරව මෙම උපාංගය භාවිත කිරීමට කර්මාන්ත ශාලා යළි සැකසීම"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"තව දැන ගැනීමට ස්පර්ශ කරන්න."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 50af3cc..d7ccda9 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -383,6 +383,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Umožňuje aplikácii používať službu okamžitých správ (IMS) na volanie bez intervencie používateľa."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"čítať stav a identitu telefónu"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Umožňuje aplikácii pristupovať k telefónnym funkciám zariadenia. Aplikácia s týmto povolením môže určiť telefónne číslo a ID zariadenia, či práve prebieha hovor, a vzdialené číslo, s ktorým je prostredníctvom hovoru nadviazané spojenie."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"čítanie telefónneho čísla"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Umožňuje aplikácii pristupovať k telefónnemu číslu daného zariadenia."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"zabránenie prechodu tabletu do režimu spánku"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"zabránenie televízoru v prechode do režimu spánku"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"deaktivovať režim spánku"</string>
@@ -649,10 +651,10 @@
     <string name="relationTypeAssistant" msgid="6274334825195379076">"Asistent"</string>
     <string name="relationTypeBrother" msgid="8757913506784067713">"Brat"</string>
     <string name="relationTypeChild" msgid="1890746277276881626">"Dieťa"</string>
-    <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"Partner(ka)"</string>
+    <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"Druh(-žka)"</string>
     <string name="relationTypeFather" msgid="5228034687082050725">"Otec"</string>
     <string name="relationTypeFriend" msgid="7313106762483391262">"Kamarát(ka)"</string>
-    <string name="relationTypeManager" msgid="6365677861610137895">"Manažér"</string>
+    <string name="relationTypeManager" msgid="6365677861610137895">"Vedúci(-a)"</string>
     <string name="relationTypeMother" msgid="4578571352962758304">"Matka"</string>
     <string name="relationTypeParent" msgid="4755635567562925226">"Rodič"</string>
     <string name="relationTypePartner" msgid="7266490285120262781">"Partner(ka)"</string>
@@ -1105,16 +1107,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 +1616,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. <xliff:g id="LABEL">%1$s</xliff:g> do práce"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. <xliff:g id="LABEL">%1$s</xliff:g> do práce"</string>
     <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>
@@ -1753,8 +1753,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Prídete o všetky zmeny a ukážka sa znova spustí o <xliff:g id="TIMEOUT">%1$s</xliff:g> s…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Zrušiť"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Resetovať"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Ak chcete toto zariadenie používať bez obmedzení, obnovte na ňom továrenské nastavenia"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Klepnutím získate ďalšie informácie."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 5bc756b..b8e38ca 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -383,6 +383,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Aplikaciji dovoljuje uporabo storitev IMS za opravljanje klicev brez vašega posredovanja."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"branje stanja in identitete telefona"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Aplikaciji omogoča dostop do funkcij telefona v napravi. S tem dovoljenjem lahko aplikacija določi telefonsko številko in ID-je naprave, določi lahko tudi, ali je klic aktiven, in oddaljeno številko, s katero je klic povezan."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"branje telefonske številke"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Aplikaciji dovoljuje dostop do telefonske številke naprave."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"preprečitev prehoda tabličnega računalnika v stanje pripravljenosti"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"preprečevanje preklopa televizorja v stanje pripravljenosti"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"preprečevanje prehoda v stanje pripravljenosti telefona"</string>
@@ -656,7 +658,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>
@@ -1105,16 +1107,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Glasnost predstavnosti"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Glasnost obvestila"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Privzeta melodija zvonjenja"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Privzeto (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Brez"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Melodije zvonjenja"</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">"Zvoki alarma"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Zvoki obvestil"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Neznano"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">Na voljo so omrežja Wi-Fi</item>
       <item quantity="two">Na voljo so omrežja Wi-Fi</item>
@@ -1618,6 +1616,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. službeni <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. službeni <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1753,8 +1753,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Morebitne spremembe bodo izgubljene in predstavitev se bo začela znova čez <xliff:g id="TIMEOUT">%1$s</xliff:g> s …"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Prekliči"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Ponastavi"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Ponastavitev naprave na tovarniške nastavitve za uporabo brez omejitev"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Dotaknite se, če želite izvedeti več."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – onemogočeno"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferenčni klic"</string>
+    <!-- no translation found for tooltip_popup_title (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index 1095088..761477e 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Lejon aplikacionin të përdorë shërbimin IMS për të kryer telefonata pa ndërhyrjen tënde."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"lexo statusin e telefonit dhe identitetin"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Lejon aplikacionin të hyjë në funksionet telefonike të pajisjes. Kjo leje i mundëson aplikacionit të përcaktojë numrin e telefonit dhe ID-të e pajisjes, nëse një telefonatë është aktive apo nëse numri në distancë është i lidhur me një telefonatë."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"lexo numrin e telefonit"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Lejon që aplikacioni të ketë qasje te numri i telefonit i pajisjes."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"parandalo kalimin e tabletit në fjetje"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"parandalo kalimin e televizorit në fjetje"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"parandalo kalimin e telefonit në fjetje"</string>
@@ -1059,16 +1061,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"volumi i klipit \"media\""</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volumi i njoftimeve"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Zile e paracaktuar."</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"I parazgjedhur (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Asnjë"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Zilet"</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">"Tingujt e alarmeve"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Tingujt e njoftimeve"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"E panjohur"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Rrjete Wi-Fi ofrohen për përdorim</item>
       <item quantity="one">Një rrjet Wi-Fi ofrohet për përdorim</item>
@@ -1564,6 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> i dytë i punës"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> i tretë i punës"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Do të humbasësh çdo ndryshim dhe demonstrimi do të niset përsëri për <xliff:g id="TIMEOUT">%1$s</xliff:g> sekonda…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Anulo"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Rivendos tani"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Rivendos cilësimet e fabrikës për ta përdorur këtë pajisje pa kufizime"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Prek për të mësuar më shumë."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> u çaktivizua"</string>
     <string name="conference_call" msgid="3751093130790472426">"Telefonatë konferencë"</string>
+    <!-- no translation found for tooltip_popup_title (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 27d7cad..f018116 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -380,6 +380,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Дозвољава апликацији да користи услугу размене тренутних порука да би упућивала позиве без ваше интервенције."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"читање статуса и идентитета телефона"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Дозвољава апликацији да приступа функцијама телефона на уређају. Ова дозвола омогућава апликацији да утврди број телефона и ИД-ове уређаја, затим да ли је позив активан, као и број даљинског уређаја са којим је успостављен позив."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"читање броја телефона"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Дозвољава апликацији да приступа броју телефона на уређају."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"спречавање преласка таблета у стање спавања"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"спречавање ТВ-а да пређе у стање спавања"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"спречавање преласка телефона у стање спавања"</string>
@@ -1082,16 +1084,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 +1589,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. пословни <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. пословни имејл <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1717,8 +1717,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Изгубићете све промене и демонстрација ће поново почети за <xliff:g id="TIMEOUT">%1$s</xliff:g> сек…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Откажи"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Ресетуј"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Ресетујте уређај на фабричка подешавања да бисте га користили без ограничења"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Додирните да бисте сазнали више."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index b048762..93504cc 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -82,10 +82,10 @@
     <string name="RuacMmi" msgid="7827887459138308886">"Avvisande av oönskade irriterande samtal"</string>
     <string name="CndMmi" msgid="3116446237081575808">"Leverans av nummer för inkommande samtal"</string>
     <string name="DndMmi" msgid="1265478932418334331">"Stör ej"</string>
-    <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Nummerpresentatören är begränsad som standard. Nästa samtal: Begränsad"</string>
-    <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Nummerpresentatörens standardinställning är begränsad. Nästa samtal: Inte begränsad"</string>
-    <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Nummerpresentatörens standardinställning är inte begränsad. Nästa samtal: Begränsad"</string>
-    <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Nummerpresentatörens standardinställning är inte begränsad. Nästa samtal: Inte begränsad"</string>
+    <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Nummerpresentatören är blockerad som standard. Nästa samtal: Blockerad"</string>
+    <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Nummerpresentatörens standardinställning är blockerad. Nästa samtal: Inte blockerad"</string>
+    <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Nummerpresentatörens standardinställning är inte blockerad. Nästa samtal: Blockerad"</string>
+    <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Nummerpresentatörens standardinställning är inte blockerad. Nästa samtal: Inte blockerad"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Tjänsten är inte etablerad."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Det går inte att ändra inställningen för nummerpresentatör."</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Datatjänsten är blockerad."</string>
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Tillåter att appen använder tjänsten för snabbmeddelanden för att ringa samtal utan åtgärd från dig."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"läsa telefonens status och identitet"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Tillåter att appen kommer åt enhetens telefonfunktioner. Med den här behörigheten tillåts appen att identifiera mobilens telefonnummer och enhets-ID, om ett samtal pågår och vilket nummer samtalet är kopplat till."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"läsa telefonnumret"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Ger appen åtkomst till mobilnumret på enheten."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"förhindra att surfplattan går in i viloläge"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"förhindra att TV:n försätts i viloläge"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"förhindra att telefonen sätts i viloläge"</string>
@@ -650,7 +652,7 @@
     <string name="relationTypeMother" msgid="4578571352962758304">"Mamma"</string>
     <string name="relationTypeParent" msgid="4755635567562925226">"Förälder"</string>
     <string name="relationTypePartner" msgid="7266490285120262781">"Partner"</string>
-    <string name="relationTypeReferredBy" msgid="101573059844135524">"Genom"</string>
+    <string name="relationTypeReferredBy" msgid="101573059844135524">"Känner genom"</string>
     <string name="relationTypeRelative" msgid="1799819930085610271">"Släkting"</string>
     <string name="relationTypeSister" msgid="1735983554479076481">"Syster"</string>
     <string name="relationTypeSpouse" msgid="394136939428698117">"Make/maka"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Andra <xliff:g id="LABEL">%1$s</xliff:g> för jobbet"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Tredje <xliff:g id="LABEL">%1$s</xliff:g> för jobbet"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Ändringar som du har gjort sparas inte och demon börjar om om <xliff:g id="TIMEOUT">%1$s</xliff:g> sekunder …"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Avbryt"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Återställ nu"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Återställ enheten till standardinställningarna om du vill använda den utan begränsningar"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Tryck här om du vill läsa mer."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 6cfd253..8d69d01 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -375,6 +375,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Huruhusu programu kutumia huduma ya IMS kupiga simu bila udhibiti wako."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"kusoma hali na kitambulisho cha simu"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Huruhusu programu kufikia vipengele vya simu vilivyo kwenye kifaa. Idhini hii inaruhusu programu kutambua nambari ya simu na kifaa, kama kuna simu inayopigwa, na nambari ya mbali iliyounganishwa kwenye simu."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"kusoma nambari ya simu"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Inaruhusu programu kufikia nambari ya simu ya kifaa."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"zuia kompyuta ndogo dhidi ya kulala"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"zuia runinga isiingie katika hali tuli"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"kuzuia simu isilale"</string>
@@ -1057,16 +1059,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 +1560,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> ya 2 ya Kazini"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> ya 3 ya Kazini"</string>
     <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>
@@ -1679,8 +1679,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Mabadiliko yoyote hayatahifadhiwa. Onyesho litaanza tena baada ya sekunde <xliff:g id="TIMEOUT">%1$s</xliff:g>..."</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Ghairi"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Weka upya sasa"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Rejesha mipangilio iliyotoka nayo kiwandani ili utumie kifaa hiki bila vikwazo"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Gusa ili kupata maelezo zaidi."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index b391912..00fa2d9 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"உங்கள் குறுக்கீடின்றி IMS சேவையைப் பயன்படுத்தி அழைப்பதற்கு, பயன்பாட்டை அனுமதிக்கும்."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"மொபைல் நிலை மற்றும் அடையாளத்தைப் படித்தல்"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"சாதனத்தின் மொபைல் அம்சங்களை அணுகப் பயன்பாட்டை அனுமதிக்கிறது. மொபைல் மற்றும் சாதன ஐடிகள், அழைப்பு செயலில் உள்ளதா மற்றும் அழைப்பு மூலம் இணைக்கப்பட்ட தொலைக் கட்டுப்பாட்டு எண் ஆகியவற்றைத் தீர்மானிக்க இந்த அனுமதி பயன்பாட்டை அனுமதிக்கிறது."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"மொபைல் எண்ணைப் படி"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"சாதனத்தின் மொபைல் எண்ணை அணுக, பயன்பாட்டை அனுமதிக்கும்."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"டேப்லெட் உறக்க நிலைக்குச் செல்வதைத் தடுத்தல்"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"டிவி உறக்கநிலைக்குச் செல்வதைத் தடுத்தல்"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"தொலைபேசி உறக்கநிலைக்குச் செல்வதைத் தடுத்தல்"</string>
@@ -1059,16 +1061,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">வைஃபை நெட்வொர்க்குகள் உள்ளன</item>
       <item quantity="one">வைஃபை நெட்வொர்க் உள்ளது</item>
@@ -1564,6 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2வது பணி <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3வது பணி <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"மாற்றங்கள் சேமிக்கப்படாது, <xliff:g id="TIMEOUT">%1$s</xliff:g> வினாடிகளில் டெமோ மீண்டும் தொடங்கும்…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"ரத்துசெய்"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"இப்போதே மீட்டமை"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"இந்தச் சாதனத்தைக் கட்டுப்பாடுகளின்றிப் பயன்படுத்த, ஆரம்ப நிலைக்கு மீட்டமைக்கவும்"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"மேலும் அறிய தொடவும்."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 5ec586f..0e3a059 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"మీ ప్రమేయం లేకుండా కాల్‌లు చేయడం కోసం IMS సేవను ఉపయోగించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"ఫోన్ స్థితి మరియు గుర్తింపుని చదవడం"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"పరికరం యొక్క ఫోన్ లక్షణాలను ప్రాప్యత చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. ఈ అనుమతి ఫోన్ నంబర్ మరియు పరికరం IDలను, కాల్ సక్రియంగా ఉందా లేదా అనే విషయాన్ని మరియు కాల్ ద్వారా కనెక్ట్ చేయబడిన రిమోట్ నంబర్‌ను కనుగొనడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ఫోన్ నంబర్‌ను చదవడం"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"పరికరం యొక్క ఫోన్ నంబర్‌ను ప్రాప్యత చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"టాబ్లెట్‌ను నిద్రావస్థకు వెళ్లనీయకుండా నిరోధించడం"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"టీవీ నిద్రావస్థకు వెళ్లకుండా నిరోధించడం"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ఫోన్‌ను నిద్రావస్థకు వెళ్లనీయకుండా నిరోధించడం"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2వ కార్యాలయం <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3వ కార్యాలయం <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"మీరు చేసిన ఏవైనా మార్పులను కోల్పోతారు మరియు డెమో <xliff:g id="TIMEOUT">%1$s</xliff:g> సెకన్లలో మళ్లీ ప్రారంభమవుతుంది…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"రద్దు చేయి"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"ఇప్పుడే రీసెట్ చేయి"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"ఈ పరికరాన్ని ఎటువంటి పరిమితులు లేకుండా ఉపయోగించడానికి ఫ్యాక్టరీ రీసెట్ చేయండి"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"మరింత తెలుసుకోవడానికి తాకండి."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 15cbd94..75afd4b 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"อนุญาตให้แอปใช้บริการ IMS เพื่อโทรออกโดยคุณไม่ต้องดำเนินการใดๆ เลย"</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"อ่านสถานะและข้อมูลระบุตัวตนของโทรศัพท์"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"อนุญาตให้แอปพลิเคชันเข้าถึงคุณลักษณะโทรศัพท์ของอุปกรณ์ การอนุญาตนี้ทำให้แอปพลิเคชันสามารถตรวจสอบหมายเลขโทรศัพท์และรหัสอุปกรณ์ ตรวจสอบว่ามีการโทรที่ทำงานอยู่หรือไม่ และตรวจสอบหมายเลขระยะไกลที่เชื่อมต่อด้วยการโทร"</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"อ่านหมายเลขโทรศัพท์"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"อนุญาตให้แอปเข้าถึงหมายเลขโทรศัพท์ของอุปกรณ์"</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ป้องกันไม่ให้แท็บเล็ตเข้าสู่โหมดสลีป"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"ป้องกันไม่ให้ทีวีเข้าสู่โหมดสลีป"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ป้องกันไม่ให้โทรศัพท์เข้าโหมดสลีป"</string>
@@ -1059,16 +1061,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">มี 1 เครือข่าย Wi-Fi ที่ใช้งานได้</item>
@@ -1553,7 +1551,7 @@
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"ลองอีกครั้งในภายหลัง"</string>
     <string name="immersive_cling_title" msgid="8394201622932303336">"กำลังดูแบบเต็มหน้าจอ"</string>
-    <string name="immersive_cling_description" msgid="3482371193207536040">"หากต้องการออกไป ให้เลื่อนลงจากด้านบน"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"หากต้องการออก ให้เลื่อนลงจากด้านบน"</string>
     <string name="immersive_cling_positive" msgid="5016839404568297683">"รับทราบ"</string>
     <string name="done_label" msgid="2093726099505892398">"เสร็จสิ้น"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"ตัวเลื่อนหมุนระบุชั่วโมง"</string>
@@ -1564,6 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> งานที่ 2"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> งานที่ 3"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"การเปลี่ยนแปลงของคุณจะหายไปและการสาธิตจะเริ่มต้นอีกครั้งใน <xliff:g id="TIMEOUT">%1$s</xliff:g> วินาที…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"ยกเลิก"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"รีเซ็ตทันที"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"รีเซ็ตเป็นค่าเริ่มต้นเพื่อใช้อุปกรณ์นี้โดยไร้ข้อจำกัด"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"แตะเพื่อเรียนรู้เพิ่มเติม"</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 31666ee..19d6b68 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Pinapahintulutan ang app na gamitin ang serbisyo ng IMS upang tumawag nang walang pahintulot mo."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"basahin ang katayuan at pagkakakilanlan ng telepono"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Pinapayagan ang app na i-access ang mga tampok ng telepono ng device. Pinapayagan ng pahintulot na ito ang app na tukuyin ang numero ng telepono at  mga ID ng device, kung aktibo man ang isang tawag, at ang malayuang numerong ikinonekta ng isang tawag."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"basahin ang numero ng telepono"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Binibigyang-daan ang app na i-access ang numero ng telepono ng device."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"pigilan ang tablet mula sa pag-sleep"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"pigilan ang TV sa pag-sleep"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"pigilan ang telepono mula sa paghinto"</string>
@@ -1059,16 +1061,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Volume ng media"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume ng notification"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Default na 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">"Wala"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Mga Ringtone"</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">"Mga tunog ng alarm"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Mga tunog ng notification"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Hindi Alam"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">Available ang mga Wi-Fi network</item>
       <item quantity="other">Available ang mga Wi-Fi network</item>
@@ -1564,6 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Pangalawang <xliff:g id="LABEL">%1$s</xliff:g> sa Trabaho"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Pangatlong <xliff:g id="LABEL">%1$s</xliff:g> sa Trabaho"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Mawawala mo ang anumang mga pagbabago at magsisimulang muli ang demo pagkalipas ng <xliff:g id="TIMEOUT">%1$s</xliff:g> (na) segundo…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Kanselahin"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"I-reset ngayon"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"I-factory reset upang magamit ang device na ito nang walang mga paghihigpit"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Pindutin upang matuto nang higit pa."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Na-disable ang <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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 0126068..b626fb9 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Uygulamanın, sizin müdahaleniz olmadan telefon etmek için IMS hizmetini kullanmasına izin verir."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"telefonun durumunu ve kimliğini okuma"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Uygulamaya cihazdaki telefon özelliklerine erişme izni verir. Bu izin, uygulamanın telefon numarasını ve cihaz kimliğini, etkin bir çağrı olup olmadığını ve çağrıda bağlanılan karşı tarafın numarasını öğrenmesine olanak sağlar."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"telefon numarasını oku"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Uygulamanın cihazın telefon numarasına erişmesine izin verir."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"tabletin uykuya geçmesini önle"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"TV\'nin uyku moduna geçmesini önleme"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"telefonun uykuya geçmesini önleme"</string>
@@ -605,7 +607,7 @@
     <string name="phoneTypeRadio" msgid="4093738079908667513">"Telsiz"</string>
     <string name="phoneTypeTelex" msgid="3367879952476250512">"Teleks"</string>
     <string name="phoneTypeTtyTdd" msgid="8606514378585000044">"TTY TDD"</string>
-    <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"İş Cep Telefonu"</string>
+    <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"İş Mobil"</string>
     <string name="phoneTypeWorkPager" msgid="649938731231157056">"İş Çağrı Cihazı"</string>
     <string name="phoneTypeAssistant" msgid="5596772636128562884">"Yardımcı"</string>
     <string name="phoneTypeMms" msgid="7254492275502768992">"MMS"</string>
@@ -649,7 +651,7 @@
     <string name="relationTypeManager" msgid="6365677861610137895">"Yönetici"</string>
     <string name="relationTypeMother" msgid="4578571352962758304">"Anne"</string>
     <string name="relationTypeParent" msgid="4755635567562925226">"Ebeveyn"</string>
-    <string name="relationTypePartner" msgid="7266490285120262781">"Hayat Arkadaşı"</string>
+    <string name="relationTypePartner" msgid="7266490285120262781">"Ortak"</string>
     <string name="relationTypeReferredBy" msgid="101573059844135524">"Öneren"</string>
     <string name="relationTypeRelative" msgid="1799819930085610271">"Akraba"</string>
     <string name="relationTypeSister" msgid="1735983554479076481">"Kız Kardeş"</string>
@@ -1059,16 +1061,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Medya ses düzeyi"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Bildirim ses düzeyi"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Varsayılan zil sesi"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Varsayılan (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Yok"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Zil sesleri"</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 sesleri"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Bildirim sesleri"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Bilinmiyor"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Kablosuz ağlar var</item>
       <item quantity="one">Kablosuz ağ var</item>
@@ -1564,6 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"İş için 2. <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"İş için 3. <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Değişiklikleri kaybedeceksiniz ve demo <xliff:g id="TIMEOUT">%1$s</xliff:g> saniye içinde tekrar başlayacak…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"İptal"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Şimdi sıfırla"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Bu cihazı kısıtlama olmadan kullanmak için fabrika ayarlarına sıfırlayın"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Daha fazla bilgi edinmek için dokunun."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> devre dışı"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferans Çağrısı"</string>
+    <!-- no translation found for tooltip_popup_title (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 104badd..05341a7 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -383,6 +383,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Додаток зможе телефонувати за допомогою служби IMS без вашого відома."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"читати статус та ідентифікаційну інформацію телефону"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Дозволяє програмі отримувати доступ до телефонних функцій пристрою. Такий дозвіл дає програмі змогу визначати номер телефону й ідентифікатори пристрою, активність виклику, а також віддалений номер, на який здійснюється виклик."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"переглядати номер телефону"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Дозволяє додатку отримувати доступ до номера телефону на пристрої."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"не доп.перехід пристр.в реж.сну"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"не допускати перехід телевізора в режим сну"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"Вимкнення режиму сну"</string>
@@ -1105,16 +1107,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 +1616,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2-а робота: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3-я робота: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1753,8 +1753,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Ви втратите всі зміни, а демонстрація знову почнеться через <xliff:g id="TIMEOUT">%1$s</xliff:g> с…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Скасувати"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Скинути"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Відновіть заводські параметри, щоб використовувати пристрій без обмежень"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Торкніться, щоб дізнатися більше."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index f8224f2..40e6624 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -265,7 +265,7 @@
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"کسی ایسی ونڈو کے مواد کا معائنہ کریں جس کے ساتھ آپ تعامل کر رہے ہیں۔"</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"ٹچ کے ذریعے دریافت کریں کو آن کرنے کی"</string>
     <string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"تھپتھپائے گئے آئٹمز کو باآواز بلند بولا جائے گا اور اشاروں کا استعمال کرکے اسکرین کو دریافت کیا جا سکتا ہے۔"</string>
-    <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"‏بہتر ویب accessibility کو آن کرنے کی"</string>
+    <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"بہتر ویب ایکسیسبیلٹی کو آن کرنے کی"</string>
     <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"ایپ کا مواد مزید قابل رسائی بنانے کیلئے اسکرپٹس کو انسٹال کیا جا سکتا ہے۔"</string>
     <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"آپکے ٹائپ کردہ متن کا مشاہدہ کرنے کی"</string>
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"اس میں ذاتی ڈیٹا جیسے کریڈٹ کارڈ نمبرز اور پاس ورڈز شامل ہیں۔"</string>
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"‏آپ کی مداخلت کے بغیر کالیں کرنے کیلئے ایپ کو IMS سروس استعمال کرنے کی اجازت دیتی ہے۔"</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"فون کے اسٹیٹس اور شناخت کو پڑھیں"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"‏ایپ کو آلے کی فون والی خصوصیات تک رسائی حاصل کرنے کی اجازت دیتا ہے۔ یہ اجازت ایپ کو فون نمبر اور آلے کے IDs کا تعین کرنے، آیا کوئی کال فعال ہے، اور کال کے ذریعہ مربوط ریموٹ نمبر کا تعین کرنے دیتی ہے۔"</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"فون نمبر پڑھے"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"ایپ کو آلہ کے فون نمبر تک رسائی کرنے دیتا ہے۔"</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ٹیبلیٹ کو سلیپ وضع میں جانے سے روکیں"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"‏TV کو سلیپ وضع میں جانے سے روکیں"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"فون کو سلیپ وضع میں جانے سے روکیں"</string>
@@ -1059,16 +1061,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>
@@ -1236,7 +1234,7 @@
     <string name="forward_intent_to_work" msgid="621480743856004612">"آپ اس ایپ کو اپنے دفتری پروفائل میں استعمال کر رہے ہیں"</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"اندراج کا طریقہ"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"مطابقت پذیری کریں"</string>
-    <string name="accessibility_binding_label" msgid="4148120742096474641">"Accessibility"</string>
+    <string name="accessibility_binding_label" msgid="4148120742096474641">"ایکسیسبیلٹی"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"وال پیپر"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"وال پیپر تبدیل کریں"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"اطلاع سننے والا"</string>
@@ -1438,9 +1436,9 @@
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"ہٹائیں"</string>
     <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"والیوم کو تجویز کردہ سطح سے زیادہ کریں؟\n\nزیادہ وقت تک اونچی آواز میں سننے سے آپ کی سماعت کو نقصان پہنچ سکتا ہے۔"</string>
-    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"‏accessibility فعال کرنے کیلئے دو انگلیاں نیچے دبائے رکھیں۔"</string>
-    <string name="accessibility_enabled" msgid="1381972048564547685">"‏Accessibility فعال۔"</string>
-    <string name="enable_accessibility_canceled" msgid="3833923257966635673">"‏Accessibility منسوخ ہوگئی۔"</string>
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"ایکسیسبیلٹی فعال کرنے کیلئے دو انگلیاں نیچے دبائے رکھیں۔"</string>
+    <string name="accessibility_enabled" msgid="1381972048564547685">"ایکسیسبیلٹی فعال۔"</string>
+    <string name="enable_accessibility_canceled" msgid="3833923257966635673">"ایکسیسبیلٹی منسوخ ہوگئی۔"</string>
     <string name="user_switched" msgid="3768006783166984410">"موجودہ صارف <xliff:g id="NAME">%1$s</xliff:g>۔"</string>
     <string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g> پر سوئچ کیا جا رہا ہے…"</string>
     <string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> لاگ آؤٹ ہو رہا ہے…"</string>
@@ -1564,6 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"دوسرا کام <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"تیسرا کام <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"آپ کی تمام تبدیلیاں ضائع ہو جائیں گی اور ڈیمو <xliff:g id="TIMEOUT">%1$s</xliff:g> سیکنڈز میں دوبارہ شروع ہوگا…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"منسوخ کریں"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"ابھی ری سیٹ کریں"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"بغیر کسی حدود کے استعمال کرنے کیلئے اس آلے کو فیکٹری ری سیٹ کریں"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"مزید جاننے کیلئے ٹچ کریں۔"</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index 78b5400..a41b323 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Ilovaga sizning ishtirokingizsiz qo‘ng‘iroqlarni amalga oshirish uchun IMS xizmatidan foydalanishga ruxsat beradi."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"telefon holati haqidagi ma’lumotlarni olish"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Ilovaga qurilmangizdagi telefon xususiyatlariga kirishga ruxsat beradi. Bu ruxsat ilovaga telefon raqami va qurilma nomlari, qo‘ng‘iroq faol yoki faolsizligi va masofadagi raqam qo‘ng‘rioq orqali bog‘langanligini aniqlashga imkon beradi."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"telefon raqamini o‘qish"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Ilovaga qurilmaning telefon raqamidan foydalanishiga ruxsat beradi."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"planshetni uyquga ketishiga yo‘l qo‘ymaslik"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"televizorning uyqu rejimiga o‘tishining oldini olish"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"telefonni uxlashiga yo‘l qo‘ymaslik"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2-ishxona <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3-ishxona <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Har qanday o‘zgarishlar o‘chib ketadi va demo <xliff:g id="TIMEOUT">%1$s</xliff:g> soniyadan so‘ng yana qayta ishga tushadi…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Bekor qilish"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Asl holatga qaytarish"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Bu qurilmadan cheklovlarsiz foydalanish uchun zavod sozlamalarini tiklang"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Ko‘proq o‘rganish uchun bosing."</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index ca5e3bc..bed672d 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Cho phép ứng dụng sử dụng dịch vụ IMS để thực hiện cuộc gọi mà không có sự can thiệp của bạn."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"đọc trạng thái và nhận dạng của điện thoại"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Cho phép ứng dụng truy cập vào các tính năng điện thoại của thiết bị. Quyền này cho phép ứng dụng xác định số điện thoại và ID thiết bị, cho dù cuộc gọi có hiện hoạt hay không và số từ xa có được kết nối bằng một cuộc gọi hay không."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"đọc số điện thoại"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Cho phép ứng dụng truy cập số điện thoại của thiết bị."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ngăn máy tính bảng chuyển sang chế độ ngủ"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"ngăn TV chuyển sang chế độ ngủ"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ngăn điện thoại chuyển sang chế độ ngủ"</string>
@@ -1059,16 +1061,12 @@
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Âm lượng phương tiện"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Âm lượng thông báo"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Nhạc chuông mặc định"</string>
-    <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
-    <skip />
+    <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Mặc định (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Không"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Nhạc chuông"</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">"Âm thanh báo thức"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Âm thanh thông báo"</string>
+    <string name="ringtone_unknown" msgid="3914515995813061520">"Không xác định"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="other">Các mạng Wi-Fi khả dụng</item>
       <item quantity="one">Mạng Wi-Fi khả dụng</item>
@@ -1564,6 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Công việc thứ 2 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Công việc thứ 2 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Bạn sẽ bị mất mọi thay đổi và bản trình diễn sẽ bắt đầu lại sau <xliff:g id="TIMEOUT">%1$s</xliff:g> giây…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Hủy"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Đặt lại ngay bây giờ"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Khôi phục cài đặt gốc để sử dụng thiết bị này mà không bị hạn chế"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Chạm để tìm hiểu thêm."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Đã tắt <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Cuộc gọi nhiều bên"</string>
+    <!-- no translation found for tooltip_popup_title (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 2126d12..9051cae 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"允许应用自行使用即时通讯服务拨打电话。"</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"读取手机状态和身份"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"允许该应用访问设备的电话功能。此权限可让该应用确定本机号码和设备 ID、是否正处于通话状态以及拨打的号码。"</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"读取电话号码"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"允许该应用访问该设备的电话号码。"</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"阻止平板电脑进入休眠状态"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"阻止电视进入休眠状态"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"防止手机休眠"</string>
@@ -1059,16 +1061,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">有可用的 WLAN 网络</item>
       <item quantity="one">有可用的 WLAN 网络</item>
@@ -1564,6 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"第二个工作<xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"第三个工作<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"您将丢失所有更改,而且演示模式将在 <xliff:g id="TIMEOUT">%1$s</xliff:g> 秒后重新启动…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"取消"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"立即重置"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"恢复出厂设置即可正常使用此设备,不受任何限制"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"触摸即可了解详情。"</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index bdd9fe3..cbb0901 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"允許應用程式自行使用 IMS 服務撥打電話。"</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"讀取手機狀態和識別碼"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"允許應用程式使用裝置的電話功能。這項權限允許應用程式確定手機號碼和裝置編號、是否正在通話中,以及所撥打的對方號碼。"</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"讀取電話號碼"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"允許應用程式存取裝置的電話號碼。"</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"防止平板電腦進入休眠狀態"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"阻止電視進入休眠狀態"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"防止手機進入休眠狀態"</string>
@@ -646,7 +648,7 @@
     <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"同居伴侶"</string>
     <string name="relationTypeFather" msgid="5228034687082050725">"父親"</string>
     <string name="relationTypeFriend" msgid="7313106762483391262">"朋友"</string>
-    <string name="relationTypeManager" msgid="6365677861610137895">"管理員"</string>
+    <string name="relationTypeManager" msgid="6365677861610137895">"主管"</string>
     <string name="relationTypeMother" msgid="4578571352962758304">"母親"</string>
     <string name="relationTypeParent" msgid="4755635567562925226">"父母"</string>
     <string name="relationTypePartner" msgid="7266490285120262781">"夥伴"</string>
@@ -1059,16 +1061,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>
@@ -1240,7 +1238,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"第二個工作<xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"第三個工作<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"系統將不會儲存變更,示範將於 <xliff:g id="TIMEOUT">%1$s</xliff:g> 秒後重新開始…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"取消"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"立即重設"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"將此裝置回復至原廠設定後,使用將不受限制"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"輕觸以瞭解詳情。"</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 3c2146b..d31dfd3 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"允許應用程式自動使用 IMS 服務撥打電話。"</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"讀取手機狀態和識別碼"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"允許應用程式使用裝置的電話功能。這項權限可讓應用程式判讀手機號碼和裝置 ID、是否正在通話中,以及所撥打的對方號碼。"</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"讀取電話號碼"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"允許應用程式存取裝置的電話號碼。"</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"防止平板電腦進入休眠狀態"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"防止電視進入休眠狀態"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"防止手機進入待命狀態"</string>
@@ -605,7 +607,7 @@
     <string name="phoneTypeRadio" msgid="4093738079908667513">"無線電"</string>
     <string name="phoneTypeTelex" msgid="3367879952476250512">"電報"</string>
     <string name="phoneTypeTtyTdd" msgid="8606514378585000044">"TTY/TDD"</string>
-    <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"公司行動電話"</string>
+    <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"公司手機"</string>
     <string name="phoneTypeWorkPager" msgid="649938731231157056">"公司呼叫器"</string>
     <string name="phoneTypeAssistant" msgid="5596772636128562884">"助理"</string>
     <string name="phoneTypeMms" msgid="7254492275502768992">"多媒體簡訊"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"第 2 項工作:<xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"第 3 項工作:<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"系統不會儲存您所做的變更,示範模式將於 <xliff:g id="TIMEOUT">%1$s</xliff:g> 秒後重新開始…"</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"取消"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"立即重設"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"恢復原廠設定即可正常使用這個裝置"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"輕觸即可瞭解詳情。"</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 (5253721848739260181) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 011e4f7..9c99c76 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -377,6 +377,8 @@
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Ivumela uhlelo lokusebenza ukuthi lusebenzise isevisi ye-IMS ukuze yenze amakholi ngaphandle kokungenelela kwakho."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"funda isimo sefoni kanye nesazisi"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Ivumela uhlelo lokusebenza ukufinyelela izici zefoni zedivayisi. Le mvume ivumela uhlelo lokusebenza ukucacisa inombolo yefoni nobunikazi bedivayisi, ukuthi noma ikholi iyasebenza, futhi nenombolo yesilawuli kude zixhunywe ngekholi."</string>
+    <string name="permlab_readPhoneNumber" msgid="6421295519255154171">"funda inombolo yefoni"</string>
+    <string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Ivumela uhlelo lokusebenza ukuthi lifinyelele kunombolo yefoni yedivayisi."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"gwema ithebhulethi ukuba ingalali"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"vimbela i-TV kusukela ekulaleni"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"gwema ifoni ukuba ingalali"</string>
@@ -1059,16 +1061,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 +1562,8 @@
     <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>
+    <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Umsebenzi wesibili <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Umsebenzi wesithathu <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <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>
@@ -1681,8 +1681,8 @@
     <string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Uzolahlekelwa inoma iluphi ushintsho futhi idemo izoqala futhi kumasekhondi angu-<xliff:g id="TIMEOUT">%1$s</xliff:g>..."</string>
     <string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Khansela"</string>
     <string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Setha kabusha manje"</string>
-    <string name="audit_safemode_notification" msgid="6416076898350685856">"Setha kabusha ukuze usebenzise idivayisi ngaphandle kwemikhawulo"</string>
-    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Thinta ukuze ufunde kabanzi."</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 (5253721848739260181) -->
+    <skip />
 </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/core/tests/coretests/src/android/provider/SettingsProviderTest.java b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
index 0a32e43..b0ce2c8 100644
--- a/core/tests/coretests/src/android/provider/SettingsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
@@ -351,6 +351,10 @@
         assertCanBeHandled(new Intent(Settings.ACTION_WIFI_SETTINGS));
         assertCanBeHandled(new Intent(Settings.ACTION_WIFI_SAVED_NETWORK_SETTINGS));
         assertCanBeHandled(new Intent(Settings.ACTION_WIRELESS_SETTINGS));
+
+        if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) {
+            assertCanBeHandled(new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS));
+        }
     }
 
     private void assertCanBeHandled(final Intent intent) {
diff --git a/docs/html/reference/images/graphics/colorspace_aces.png b/docs/html/reference/images/graphics/colorspace_aces.png
new file mode 100644
index 0000000..efafe5c
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_aces.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_acescg.png b/docs/html/reference/images/graphics/colorspace_acescg.png
new file mode 100644
index 0000000..55f6ab5
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_acescg.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_adobe_rgb.png b/docs/html/reference/images/graphics/colorspace_adobe_rgb.png
new file mode 100644
index 0000000..cb7d602
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_adobe_rgb.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_bt2020.png b/docs/html/reference/images/graphics/colorspace_bt2020.png
new file mode 100644
index 0000000..34a3853
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_bt2020.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_bt709.png b/docs/html/reference/images/graphics/colorspace_bt709.png
new file mode 100644
index 0000000..ba637f5
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_bt709.png
Binary files differ
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_dci_p3.png b/docs/html/reference/images/graphics/colorspace_dci_p3.png
new file mode 100644
index 0000000..19144e7
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_dci_p3.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_display_p3.png b/docs/html/reference/images/graphics/colorspace_display_p3.png
new file mode 100644
index 0000000..a86c60a
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_display_p3.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_ntsc_1953.png b/docs/html/reference/images/graphics/colorspace_ntsc_1953.png
new file mode 100644
index 0000000..bce93da
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_ntsc_1953.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_pro_photo_rgb.png b/docs/html/reference/images/graphics/colorspace_pro_photo_rgb.png
new file mode 100644
index 0000000..74c95be
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_pro_photo_rgb.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/docs/html/reference/images/graphics/colorspace_scrgb.png b/docs/html/reference/images/graphics/colorspace_scrgb.png
new file mode 100644
index 0000000..2351b8e
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_scrgb.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_smpte_c.png b/docs/html/reference/images/graphics/colorspace_smpte_c.png
new file mode 100644
index 0000000..360bb73
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_smpte_c.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_srgb.png b/docs/html/reference/images/graphics/colorspace_srgb.png
new file mode 100644
index 0000000..ba637f5
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_srgb.png
Binary files differ
diff --git a/docs/html/reference/packages-wearable-support.html b/docs/html/reference/packages-wearable-support.html
index aff2e34..a8d9446 100644
--- a/docs/html/reference/packages-wearable-support.html
+++ b/docs/html/reference/packages-wearable-support.html
@@ -113,7 +113,7 @@
 
 
 <!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
 <script src="../assets/js/android_3p-bundle.js" type="text/javascript"></script>
 <script type="text/javascript">
   var toRoot = "../";
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index d114deb..7dc5de3 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -16,11 +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;
 
 /**
@@ -117,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 {
@@ -207,6 +239,11 @@
      * ColorSpace cs = ColorSpace.get(ColorSpace.Named.DCI_P3);
      * </pre>
      *
+     * <p>The properties of each color space are described below (see {@link #SRGB sRGB}
+     * for instance). When applicable, the color gamut of each color space is compared
+     * to the color gamut of sRGB using a CIE 1931 xy chromaticity diagram. This diagram
+     * shows the location of the color space's primaries and white point.</p>
+     *
      * @see ColorSpace#get(Named)
      */
     public enum Named {
@@ -240,6 +277,10 @@
          *     </tr>
          *     <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr>
          * </table>
+         * <p>
+         *     <img src="{@docRoot}reference/android/images/graphics/colorspace_srgb.png" />
+         *     <figcaption style="text-align: center;">sRGB</figcaption>
+         * </p>
          */
         SRGB,
         /**
@@ -263,6 +304,10 @@
          *     </tr>
          *     <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr>
          * </table>
+         * <p>
+         *     <img src="{@docRoot}reference/android/images/graphics/colorspace_srgb.png" />
+         *     <figcaption style="text-align: center;">sRGB</figcaption>
+         * </p>
          */
         LINEAR_SRGB,
         /**
@@ -298,6 +343,10 @@
          *     </tr>
          *     <tr><td>Range</td><td colspan="4">\([-0.5..7.5[\)</td></tr>
          * </table>
+         * <p>
+         *     <img src="{@docRoot}reference/android/images/graphics/colorspace_scrgb.png" />
+         *     <figcaption style="text-align: center;">Extended RGB (orange) vs sRGB (white)</figcaption>
+         * </p>
          */
         EXTENDED_SRGB,
         /**
@@ -321,6 +370,10 @@
          *     </tr>
          *     <tr><td>Range</td><td colspan="4">\([-0.5..7.5[\)</td></tr>
          * </table>
+         * <p>
+         *     <img src="{@docRoot}reference/android/images/graphics/colorspace_scrgb.png" />
+         *     <figcaption style="text-align: center;">Extended RGB (orange) vs sRGB (white)</figcaption>
+         * </p>
          */
         LINEAR_EXTENDED_SRGB,
         /**
@@ -352,6 +405,10 @@
          *     </tr>
          *     <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr>
          * </table>
+         * <p>
+         *     <img src="{@docRoot}reference/android/images/graphics/colorspace_bt709.png" />
+         *     <figcaption style="text-align: center;">BT.709</figcaption>
+         * </p>
          */
         BT709,
         /**
@@ -383,6 +440,10 @@
          *     </tr>
          *     <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr>
          * </table>
+         * <p>
+         *     <img src="{@docRoot}reference/android/images/graphics/colorspace_bt2020.png" />
+         *     <figcaption style="text-align: center;">BT.2020 (orange) vs sRGB (white)</figcaption>
+         * </p>
          */
         BT2020,
         /**
@@ -406,6 +467,10 @@
          *     </tr>
          *     <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr>
          * </table>
+         * <p>
+         *     <img src="{@docRoot}reference/android/images/graphics/colorspace_dci_p3.png" />
+         *     <figcaption style="text-align: center;">DCI-P3 (orange) vs sRGB (white)</figcaption>
+         * </p>
          */
         DCI_P3,
         /**
@@ -437,6 +502,10 @@
          *     </tr>
          *     <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr>
          * </table>
+         * <p>
+         *     <img src="{@docRoot}reference/android/images/graphics/colorspace_display_p3.png" />
+         *     <figcaption style="text-align: center;">Display P3 (orange) vs sRGB (white)</figcaption>
+         * </p>
          */
         DISPLAY_P3,
         /**
@@ -468,6 +537,10 @@
          *     </tr>
          *     <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr>
          * </table>
+         * <p>
+         *     <img src="{@docRoot}reference/android/images/graphics/colorspace_ntsc_1953.png" />
+         *     <figcaption style="text-align: center;">NTSC 1953 (orange) vs sRGB (white)</figcaption>
+         * </p>
          */
         NTSC_1953,
         /**
@@ -499,6 +572,10 @@
          *     </tr>
          *     <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr>
          * </table>
+         * <p>
+         *     <img src="{@docRoot}reference/android/images/graphics/colorspace_smpte_c.png" />
+         *     <figcaption style="text-align: center;">SMPTE-C (orange) vs sRGB (white)</figcaption>
+         * </p>
          */
         SMPTE_C,
         /**
@@ -522,6 +599,10 @@
          *     </tr>
          *     <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr>
          * </table>
+         * <p>
+         *     <img src="{@docRoot}reference/android/images/graphics/colorspace_adobe_rgb.png" />
+         *     <figcaption style="text-align: center;">Adobe RGB (orange) vs sRGB (white)</figcaption>
+         * </p>
          */
         ADOBE_RGB,
         /**
@@ -553,6 +634,10 @@
          *     </tr>
          *     <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr>
          * </table>
+         * <p>
+         *     <img src="{@docRoot}reference/android/images/graphics/colorspace_pro_photo_rgb.png" />
+         *     <figcaption style="text-align: center;">ProPhoto RGB (orange) vs sRGB (white)</figcaption>
+         * </p>
          */
         PRO_PHOTO_RGB,
         /**
@@ -576,6 +661,10 @@
          *     </tr>
          *     <tr><td>Range</td><td colspan="4">\([-65504.0, 65504.0]\)</td></tr>
          * </table>
+         * <p>
+         *     <img src="{@docRoot}reference/android/images/graphics/colorspace_aces.png" />
+         *     <figcaption style="text-align: center;">ACES (orange) vs sRGB (white)</figcaption>
+         * </p>
          */
         ACES,
         /**
@@ -599,6 +688,10 @@
          *     </tr>
          *     <tr><td>Range</td><td colspan="4">\([-65504.0, 65504.0]\)</td></tr>
          * </table>
+         * <p>
+         *     <img src="{@docRoot}reference/android/images/graphics/colorspace_acescg.png" />
+         *     <figcaption style="text-align: center;">ACEScg (orange) vs sRGB (white)</figcaption>
+         * </p>
          */
         ACESCG,
         /**
@@ -1110,7 +1203,7 @@
         if (source.equals(destination)) return Connector.identity(source);
 
         if (source.getModel() == Model.RGB && destination.getModel() == Model.RGB) {
-            return new Connector.RGB((Rgb) source, (Rgb) destination, intent);
+            return new Connector.Rgb((Rgb) source, (Rgb) destination, intent);
         }
 
         return new Connector(source, destination, intent);
@@ -1162,7 +1255,7 @@
         if (source.isSrgb()) return Connector.identity(source);
 
         if (source.getModel() == Model.RGB) {
-            return new Connector.RGB((Rgb) source, (Rgb) get(Named.SRGB), intent);
+            return new Connector.Rgb((Rgb) source, (Rgb) get(Named.SRGB), intent);
         }
 
         return new Connector(source, get(Named.SRGB), intent);
@@ -1271,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",
@@ -1740,6 +1847,11 @@
      * primaries and white point in the CIE XYZ space. The tristimulus XYZ values
      * are internally converted to xyY.</p>
      *
+     * <p>
+     *     <img src="{@docRoot}reference/android/images/graphics/colorspace_srgb.png" />
+     *     <figcaption style="text-align: center;">sRGB primaries and white point</figcaption>
+     * </p>
+     *
      * <h3>Transfer functions</h3>
      * <p>A transfer function is a color component conversion function, defined as
      * a single variable, monotonic mathematical function. It is applied to each
@@ -1788,6 +1900,11 @@
      * range \([-0.5..7.5]\) while {@link Named#ACES ACES} can be used throughout
      * the range \([-65504, 65504]\).</p>
      *
+     * <p>
+     *     <img src="{@docRoot}reference/android/images/graphics/colorspace_scrgb.png" />
+     *     <figcaption style="text-align: center;">Extended sRGB and its large range</figcaption>
+     * </p>
+     *
      * <h3>Converting between RGB color spaces</h3>
      * <p>Conversion between two color spaces is achieved by using an intermediate
      * color space called the profile connection space (PCS). The PCS used by
@@ -1854,7 +1971,7 @@
                 @NonNull @Size(9) float[] toXYZ,
                 @NonNull DoubleUnaryOperator oetf,
                 @NonNull DoubleUnaryOperator eotf) {
-            this(name,computePrimaries(toXYZ, eotf), computeWhitePoint(toXYZ, eotf),
+            this(name, computePrimaries(toXYZ, eotf), computeWhitePoint(toXYZ, eotf),
                     oetf, eotf, 0.0f, 1.0f, MIN_ID);
         }
 
@@ -1996,8 +2113,8 @@
 
             // A color space is wide-gamut if its area is >90% of NTSC 1953 and
             // if it entirely contains the Color space definition in xyY
-            mIsWideGamut = isWideGamut(primaries, min, max);
-            mIsSrgb = isSrgb(primaries, whitePoint, oetf, eotf, min, max, id);
+            mIsWideGamut = isWideGamut(mPrimaries, min, max);
+            mIsSrgb = isSrgb(mPrimaries, mWhitePoint, oetf, eotf, min, max, id);
         }
 
         /**
@@ -2450,7 +2567,7 @@
          * If the conditions above are not met, the color space is considered as having
          * a wide color gamut if its range is larger than [0..1].
          *
-         * @param primaries RGB primaries in CIE xyY or XYZ as an array of 6 or 9 floats
+         * @param primaries RGB primaries in CIE xyY as an array of 6 floats
          * @param min The minimum value of the color space's range
          * @param max The minimum value of the color space's range
          * @return True if the color space has a wide gamut, false otherwise
@@ -2458,7 +2575,7 @@
          * @see #isWideGamut()
          * @see #area(float[])
          */
-        private static boolean isWideGamut(@NonNull @Size(min = 6, max = 9) float[] primaries,
+        private static boolean isWideGamut(@NonNull @Size(6) float[] primaries,
                 float min, float max) {
             return (area(primaries) / area(NTSC_1953_PRIMARIES) > 0.9f &&
                             contains(primaries, SRGB_PRIMARIES)) || (min < 0.0f && max > 1.0f);
@@ -2643,7 +2760,7 @@
          * @return A new array of 6 floats containing the primaries in xyY
          */
         @NonNull
-        @Size(2)
+        @Size(6)
         private static float[] xyPrimaries(@NonNull @Size(min = 6, max = 9) float[] primaries) {
             float[] xyPrimaries = new float[6];
 
@@ -2818,7 +2935,7 @@
         private Connector(
                 @NonNull ColorSpace source, @NonNull ColorSpace destination,
                 @NonNull ColorSpace transformSource, @NonNull ColorSpace transformDestination,
-                @NonNull RenderIntent intent, @NonNull @Size(3) float[] transform) {
+                @NonNull RenderIntent intent, @Nullable @Size(3) float[] transform) {
             mSource = source;
             mDestination = destination;
             mTransformSource = transformSource;
@@ -2938,13 +3055,12 @@
         /**
          * Optimized connector for RGB->RGB conversions.
          */
-        private static class RGB extends Connector {
+        private static class Rgb extends Connector {
             @NonNull private final ColorSpace.Rgb mSource;
             @NonNull private final ColorSpace.Rgb mDestination;
             @NonNull private final float[] mTransform;
 
-            RGB(@NonNull ColorSpace.Rgb source,
-                    @NonNull ColorSpace.Rgb destination,
+            Rgb(@NonNull ColorSpace.Rgb source, @NonNull ColorSpace.Rgb destination,
                     @NonNull RenderIntent intent) {
                 super(source, destination, source, destination, intent, null);
                 mSource = source;
@@ -3042,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/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index abdc2b9..d88aee9 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -1128,8 +1128,6 @@
 
             createAllFutures();
 
-            mCheckedOpacity = true;
-
             final int N = mNumChildren;
             final Drawable[] drawables = mDrawables;
             int op = (N > 0) ? drawables[0].getOpacity() : PixelFormat.TRANSPARENT;
@@ -1138,6 +1136,7 @@
             }
 
             mOpacity = op;
+            mCheckedOpacity = true;
             return op;
         }
 
@@ -1148,19 +1147,19 @@
 
             createAllFutures();
 
-            mCheckedStateful = true;
-
             final int N = mNumChildren;
             final Drawable[] drawables = mDrawables;
+            boolean isStateful = false;
             for (int i = 0; i < N; i++) {
                 if (drawables[i].isStateful()) {
-                    mStateful = true;
-                    return true;
+                    isStateful = true;
+                    break;
                 }
             }
 
-            mStateful = false;
-            return false;
+            mStateful = isStateful;
+            mCheckedStateful = true;
+            return isStateful;
         }
 
         public void growArray(int oldSize, int newSize) {
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/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index e09fea5..355e45e 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -137,7 +137,7 @@
             layers[i].setCallback(this);
             mLayerState.mChildrenChangingConfigurations |= layers[i].getChangingConfigurations();
         }
-        mLayerState.mNum = length;
+        mLayerState.mNumChildren = length;
         mLayerState.mChildren = r;
 
         ensurePadding();
@@ -154,7 +154,7 @@
      */
     LayerDrawable(@Nullable LayerState state, @Nullable Resources res) {
         mLayerState = createConstantState(state, res);
-        if (mLayerState.mNum > 0) {
+        if (mLayerState.mNumChildren > 0) {
             ensurePadding();
             refreshPadding();
         }
@@ -185,7 +185,7 @@
         a.recycle();
 
         final ChildDrawable[] array = state.mChildren;
-        final int N = state.mNum;
+        final int N = state.mNumChildren;
         for (int i = 0; i < N; i++) {
             final ChildDrawable layer = array[i];
             layer.setDensity(density);
@@ -217,7 +217,7 @@
         }
 
         final ChildDrawable[] array = state.mChildren;
-        final int N = state.mNum;
+        final int N = state.mNumChildren;
         for (int i = 0; i < N; i++) {
             final ChildDrawable layer = array[i];
             layer.setDensity(density);
@@ -416,7 +416,7 @@
         }
 
         final ChildDrawable[] layers = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             if (layers[i].mDrawable.isProjected()) {
                 return true;
@@ -435,7 +435,7 @@
     int addLayer(@NonNull ChildDrawable layer) {
         final LayerState st = mLayerState;
         final int N = st.mChildren != null ? st.mChildren.length : 0;
-        final int i = st.mNum;
+        final int i = st.mNumChildren;
         if (i >= N) {
             final ChildDrawable[] nu = new ChildDrawable[N + 10];
             if (i > 0) {
@@ -446,7 +446,7 @@
         }
 
         st.mChildren[i] = layer;
-        st.mNum++;
+        st.mNumChildren++;
         st.invalidateCache();
         return i;
     }
@@ -514,7 +514,7 @@
      */
     public Drawable findDrawableByLayerId(int id) {
         final ChildDrawable[] layers = mLayerState.mChildren;
-        for (int i = mLayerState.mNum - 1; i >= 0; i--) {
+        for (int i = mLayerState.mNumChildren - 1; i >= 0; i--) {
             if (layers[i].mId == id) {
                 return layers[i].mDrawable;
             }
@@ -549,7 +549,7 @@
      * @attr ref android.R.styleable#LayerDrawableItem_id
      */
     public int getId(int index) {
-        if (index >= mLayerState.mNum) {
+        if (index >= mLayerState.mNumChildren) {
             throw new IndexOutOfBoundsException();
         }
         return mLayerState.mChildren[index].mId;
@@ -561,7 +561,7 @@
      * @return The number of layers.
      */
     public int getNumberOfLayers() {
-        return mLayerState.mNum;
+        return mLayerState.mNumChildren;
     }
 
     /**
@@ -593,7 +593,7 @@
      */
     public int findIndexByLayerId(int id) {
         final ChildDrawable[] layers = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             final ChildDrawable childDrawable = layers[i];
             if (childDrawable.mId == id) {
@@ -615,7 +615,7 @@
      * @attr ref android.R.styleable#LayerDrawableItem_drawable
      */
     public void setDrawable(int index, Drawable drawable) {
-        if (index >= mLayerState.mNum) {
+        if (index >= mLayerState.mNumChildren) {
             throw new IndexOutOfBoundsException();
         }
 
@@ -651,7 +651,7 @@
      * @attr ref android.R.styleable#LayerDrawableItem_drawable
      */
     public Drawable getDrawable(int index) {
-        if (index >= mLayerState.mNum) {
+        if (index >= mLayerState.mNumChildren) {
             throw new IndexOutOfBoundsException();
         }
         return mLayerState.mChildren[index].mDrawable;
@@ -1003,7 +1003,7 @@
     @Override
     public void draw(Canvas canvas) {
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             final Drawable dr = array[i].mDrawable;
             if (dr != null) {
@@ -1230,7 +1230,7 @@
 
         // Add all the padding.
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             refreshChildPadding(i, array[i]);
 
@@ -1249,7 +1249,7 @@
 
         // Take the max padding.
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             refreshChildPadding(i, array[i]);
 
@@ -1268,7 +1268,7 @@
     @Override
     public void getOutline(@NonNull Outline outline) {
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             final Drawable dr = array[i].mDrawable;
             if (dr != null) {
@@ -1283,7 +1283,7 @@
     @Override
     public void setHotspot(float x, float y) {
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             final Drawable dr = array[i].mDrawable;
             if (dr != null) {
@@ -1295,7 +1295,7 @@
     @Override
     public void setHotspotBounds(int left, int top, int right, int bottom) {
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             final Drawable dr = array[i].mDrawable;
             if (dr != null) {
@@ -1323,7 +1323,7 @@
     public boolean setVisible(boolean visible, boolean restart) {
         final boolean changed = super.setVisible(visible, restart);
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             final Drawable dr = array[i].mDrawable;
             if (dr != null) {
@@ -1337,7 +1337,7 @@
     @Override
     public void setDither(boolean dither) {
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             final Drawable dr = array[i].mDrawable;
             if (dr != null) {
@@ -1349,7 +1349,7 @@
     @Override
     public void setAlpha(int alpha) {
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             final Drawable dr = array[i].mDrawable;
             if (dr != null) {
@@ -1371,7 +1371,7 @@
     @Override
     public void setColorFilter(ColorFilter colorFilter) {
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             final Drawable dr = array[i].mDrawable;
             if (dr != null) {
@@ -1383,7 +1383,7 @@
     @Override
     public void setTintList(ColorStateList tint) {
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             final Drawable dr = array[i].mDrawable;
             if (dr != null) {
@@ -1395,7 +1395,7 @@
     @Override
     public void setTintMode(Mode tintMode) {
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             final Drawable dr = array[i].mDrawable;
             if (dr != null) {
@@ -1406,7 +1406,7 @@
 
     private Drawable getFirstNonNullDrawable() {
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             final Drawable dr = array[i].mDrawable;
             if (dr != null) {
@@ -1444,7 +1444,7 @@
         mLayerState.mAutoMirrored = mirrored;
 
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             final Drawable dr = array[i].mDrawable;
             if (dr != null) {
@@ -1461,7 +1461,7 @@
     @Override
     public void jumpToCurrentState() {
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             final Drawable dr = array[i].mDrawable;
             if (dr != null) {
@@ -1480,7 +1480,7 @@
         boolean changed = false;
 
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             final Drawable dr = array[i].mDrawable;
             if (dr != null && dr.isStateful() && dr.setState(state)) {
@@ -1501,7 +1501,7 @@
         boolean changed = false;
 
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             final Drawable dr = array[i].mDrawable;
             if (dr != null && dr.setLevel(level)) {
@@ -1543,7 +1543,7 @@
         final boolean isPaddingNested = mLayerState.mPaddingMode == PADDING_MODE_NEST;
         final ChildDrawable[] array = mLayerState.mChildren;
 
-        for (int i = 0, count = mLayerState.mNum; i < count; i++) {
+        for (int i = 0, count = mLayerState.mNumChildren; i < count; i++) {
             final ChildDrawable r = array[i];
             final Drawable d = r.mDrawable;
             if (d == null) {
@@ -1642,7 +1642,7 @@
         final boolean nest = mLayerState.mPaddingMode == PADDING_MODE_NEST;
         final boolean isLayoutRtl = getLayoutDirection() == LayoutDirection.RTL;
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             final ChildDrawable r = array[i];
             if (r.mDrawable == null) {
@@ -1684,7 +1684,7 @@
 
         final boolean nest = mLayerState.mPaddingMode == PADDING_MODE_NEST;
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             final ChildDrawable r = array[i];
             if (r.mDrawable == null) {
@@ -1733,7 +1733,7 @@
      * Ensures the child padding caches are large enough.
      */
     void ensurePadding() {
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         if (mPaddingL != null && mPaddingL.length >= N) {
             return;
         }
@@ -1745,7 +1745,7 @@
     }
 
     void refreshPadding() {
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         final ChildDrawable[] array = mLayerState.mChildren;
         for (int i = 0; i < N; i++) {
             refreshChildPadding(i, array[i]);
@@ -1766,7 +1766,7 @@
         if (!mMutated && super.mutate() == this) {
             mLayerState = createConstantState(mLayerState, null);
             final ChildDrawable[] array = mLayerState.mChildren;
-            final int N = mLayerState.mNum;
+            final int N = mLayerState.mNumChildren;
             for (int i = 0; i < N; i++) {
                 final Drawable dr = array[i].mDrawable;
                 if (dr != null) {
@@ -1785,7 +1785,7 @@
         super.clearMutated();
 
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             final Drawable dr = array[i].mDrawable;
             if (dr != null) {
@@ -1800,7 +1800,7 @@
         boolean changed = false;
 
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             final Drawable dr = array[i].mDrawable;
             if (dr != null) {
@@ -1905,7 +1905,7 @@
     static class LayerState extends ConstantState {
         private int[] mThemeAttrs;
 
-        int mNum;
+        int mNumChildren;
         ChildDrawable[] mChildren;
 
         int mDensity;
@@ -1922,10 +1922,10 @@
         @Config int mChangingConfigurations;
         @Config int mChildrenChangingConfigurations;
 
-        private boolean mHaveOpacity;
+        private boolean mCheckedOpacity;
         private int mOpacity;
 
-        private boolean mHaveIsStateful;
+        private boolean mCheckedStateful;
         private boolean mIsStateful;
 
         private boolean mAutoMirrored = false;
@@ -1938,9 +1938,9 @@
 
             if (orig != null) {
                 final ChildDrawable[] origChildDrawable = orig.mChildren;
-                final int N = orig.mNum;
+                final int N = orig.mNumChildren;
 
-                mNum = N;
+                mNumChildren = N;
                 mChildren = new ChildDrawable[N];
 
                 mChangingConfigurations = orig.mChangingConfigurations;
@@ -1951,9 +1951,9 @@
                     mChildren[i] = new ChildDrawable(or, owner, res);
                 }
 
-                mHaveOpacity = orig.mHaveOpacity;
+                mCheckedOpacity = orig.mCheckedOpacity;
                 mOpacity = orig.mOpacity;
-                mHaveIsStateful = orig.mHaveIsStateful;
+                mCheckedStateful = orig.mCheckedStateful;
                 mIsStateful = orig.mIsStateful;
                 mAutoMirrored = orig.mAutoMirrored;
                 mPaddingMode = orig.mPaddingMode;
@@ -1970,7 +1970,7 @@
                     applyDensityScaling(orig.mDensity, mDensity);
                 }
             } else {
-                mNum = 0;
+                mNumChildren = 0;
                 mChildren = null;
             }
         }
@@ -2022,7 +2022,7 @@
             }
 
             final ChildDrawable[] array = mChildren;
-            final int N = mNum;
+            final int N = mNumChildren;
             for (int i = 0; i < N; i++) {
                 final ChildDrawable layer = array[i];
                 if (layer.canApplyTheme()) {
@@ -2050,12 +2050,12 @@
         }
 
         public final int getOpacity() {
-            if (mHaveOpacity) {
+            if (mCheckedOpacity) {
                 return mOpacity;
             }
 
+            final int N = mNumChildren;
             final ChildDrawable[] array = mChildren;
-            final int N = mNum;
 
             // Seek to the first non-null drawable.
             int firstIndex = -1;
@@ -2082,17 +2082,17 @@
             }
 
             mOpacity = op;
-            mHaveOpacity = true;
+            mCheckedOpacity = true;
             return op;
         }
 
         public final boolean isStateful() {
-            if (mHaveIsStateful) {
+            if (mCheckedStateful) {
                 return mIsStateful;
             }
 
+            final int N = mNumChildren;
             final ChildDrawable[] array = mChildren;
-            final int N = mNum;
             boolean isStateful = false;
             for (int i = 0; i < N; i++) {
                 final Drawable dr = array[i].mDrawable;
@@ -2103,13 +2103,13 @@
             }
 
             mIsStateful = isStateful;
-            mHaveIsStateful = true;
+            mCheckedStateful = true;
             return isStateful;
         }
 
         public final boolean canConstantState() {
             final ChildDrawable[] array = mChildren;
-            final int N = mNum;
+            final int N = mNumChildren;
             for (int i = 0; i < N; i++) {
                 final Drawable dr = array[i].mDrawable;
                 if (dr != null && dr.getConstantState() == null) {
@@ -2122,8 +2122,8 @@
         }
 
         public void invalidateCache() {
-            mHaveOpacity = false;
-            mHaveIsStateful = false;
+            mCheckedOpacity = false;
+            mCheckedStateful = false;
         }
 
     }
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index caf2e7a..f83c160 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -667,7 +667,7 @@
     public void getOutline(@NonNull Outline outline) {
         final LayerState state = mLayerState;
         final ChildDrawable[] children = state.mChildren;
-        final int N = state.mNum;
+        final int N = state.mNumChildren;
         for (int i = 0; i < N; i++) {
             if (children[i].mId != R.id.mask) {
                 children[i].mDrawable.getOutline(outline);
@@ -815,7 +815,7 @@
 
         // Check for non-opaque, non-mask content.
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int count = mLayerState.mNum;
+        final int count = mLayerState.mNumChildren;
         for (int i = 0; i < count; i++) {
             if (array[i].mDrawable.getOpacity() != PixelFormat.OPAQUE) {
                 return MASK_CONTENT;
@@ -829,7 +829,7 @@
     private void drawContent(Canvas canvas) {
         // Draw everything except the mask.
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int count = mLayerState.mNum;
+        final int count = mLayerState.mNumChildren;
         for (int i = 0; i < count; i++) {
             if (array[i].mId != R.id.mask) {
                 array[i].mDrawable.draw(canvas);
@@ -1045,7 +1045,7 @@
         mLayerState = mState;
         mDensity = Drawable.resolveDensity(res, mState.mDensity);
 
-        if (mState.mNum > 0) {
+        if (mState.mNumChildren > 0) {
             ensurePadding();
             refreshPadding();
         }
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 ad1ead8..68c51ef 100644
--- a/libs/androidfw/Android.mk
+++ b/libs/androidfw/Android.mk
@@ -14,73 +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_STATIC_LIBRARIES := libziparchive libbase
-LOCAL_SHARED_LIBRARIES := \
-    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..f5aef05 100644
--- a/libs/androidfw/AttributeResolution.cpp
+++ b/libs/androidfw/AttributeResolution.cpp
@@ -14,34 +14,41 @@
  * limitations under the License.
  */
 
-#include "AttributeFinder.h"
-
 #include "androidfw/AttributeResolution.h"
-#include "androidfw/ResourceTypes.h"
+
+#include <cstdint>
 
 #include <android/log.h>
-#include <cstdint>
+
+#include "androidfw/AttributeFinder.h"
+#include "androidfw/ResourceTypes.h"
 
 constexpr bool kDebugStyles = false;
 
 namespace android {
 
-class XmlAttributeFinder : public BackTrackingAttributeFinder<XmlAttributeFinder, size_t> {
+class XmlAttributeFinder
+    : public BackTrackingAttributeFinder<XmlAttributeFinder, size_t> {
  public:
   explicit XmlAttributeFinder(const ResXMLParser* parser)
-      : BackTrackingAttributeFinder(0, parser != NULL ? parser->getAttributeCount() : 0),
+      : BackTrackingAttributeFinder(
+            0, parser != nullptr ? parser->getAttributeCount() : 0),
         parser_(parser) {}
 
-  inline uint32_t GetAttribute(size_t index) const { return parser_->getAttributeNameResID(index); }
+  inline uint32_t GetAttribute(size_t index) const {
+    return parser_->getAttributeNameResID(index);
+  }
 
  private:
   const ResXMLParser* parser_;
 };
 
 class BagAttributeFinder
-    : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> {
+    : public BackTrackingAttributeFinder<BagAttributeFinder,
+                                         const ResTable::bag_entry*> {
  public:
-  BagAttributeFinder(const ResTable::bag_entry* start, const ResTable::bag_entry* end)
+  BagAttributeFinder(const ResTable::bag_entry* start,
+                     const ResTable::bag_entry* end)
       : BackTrackingAttributeFinder(start, end) {}
 
   inline uint32_t GetAttribute(const ResTable::bag_entry* entry) const {
@@ -49,12 +56,14 @@
   }
 };
 
-bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr, uint32_t def_style_res,
-                  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 ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr,
+                  uint32_t def_style_res, uint32_t* src_values,
+                  size_t src_values_length, 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", theme, def_style_attr,
-          def_style_res);
+    ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x", theme,
+          def_style_attr, def_style_res);
   }
 
   const ResTable& res = theme->getResTable();
@@ -67,7 +76,8 @@
   uint32_t def_style_bag_type_set_flags = 0;
   if (def_style_attr != 0) {
     Res_value value;
-    if (theme->getAttribute(def_style_attr, &value, &def_style_bag_type_set_flags) >= 0) {
+    if (theme->getAttribute(def_style_attr, &value,
+                            &def_style_bag_type_set_flags) >= 0) {
       if (value.dataType == Res_value::TYPE_REFERENCE) {
         def_style_res = value.data;
       }
@@ -78,14 +88,15 @@
   res.lock();
 
   // Retrieve the default style bag, if requested.
-  const ResTable::bag_entry* def_style_start = NULL;
+  const ResTable::bag_entry* def_style_start = nullptr;
   uint32_t def_style_type_set_flags = 0;
-  ssize_t bag_off =
-      def_style_res != 0
-          ? res.getBagLocked(def_style_res, &def_style_start, &def_style_type_set_flags)
-          : -1;
+  ssize_t bag_off = def_style_res != 0
+                        ? res.getBagLocked(def_style_res, &def_style_start,
+                                           &def_style_type_set_flags)
+                        : -1;
   def_style_type_set_flags |= def_style_bag_type_set_flags;
-  const ResTable::bag_entry* const def_style_end = def_style_start + (bag_off >= 0 ? bag_off : 0);
+  const ResTable::bag_entry* const def_style_end =
+      def_style_start + (bag_off >= 0 ? bag_off : 0);
   BagAttributeFinder def_style_attr_finder(def_style_start, def_style_end);
 
   // Now iterate through all of the attributes that the client has requested,
@@ -113,18 +124,21 @@
       value.dataType = Res_value::TYPE_ATTRIBUTE;
       value.data = src_values[ii];
       if (kDebugStyles) {
-        ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data);
+        ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType,
+              value.data);
       }
     }
 
     if (value.dataType == Res_value::TYPE_NULL) {
-      const ResTable::bag_entry* const def_style_entry = def_style_attr_finder.Find(cur_ident);
+      const ResTable::bag_entry* const def_style_entry =
+          def_style_attr_finder.Find(cur_ident);
       if (def_style_entry != def_style_end) {
         block = def_style_entry->stringBlock;
         type_set_flags = def_style_type_set_flags;
         value = def_style_entry->map.value;
         if (kDebugStyles) {
-          ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
+          ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType,
+                value.data);
         }
       }
     }
@@ -132,24 +146,29 @@
     uint32_t resid = 0;
     if (value.dataType != Res_value::TYPE_NULL) {
       // Take care of resolving the found resource to its final value.
-      ssize_t new_block =
-          theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config);
+      ssize_t new_block = theme->resolveAttributeReference(
+          &value, block, &resid, &type_set_flags, &config);
       if (new_block >= 0) block = new_block;
       if (kDebugStyles) {
-        ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
+        ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType,
+              value.data);
       }
     } else {
       // If we still don't have a value for this attribute, try to find
       // it in the theme!
-      ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags);
+      ssize_t new_block =
+          theme->getAttribute(cur_ident, &value, &type_set_flags);
       if (new_block >= 0) {
         if (kDebugStyles) {
-          ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
+          ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType,
+                value.data);
         }
-        new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config);
+        new_block = res.resolveReference(&value, new_block, &resid,
+                                         &type_set_flags, &config);
         if (new_block >= 0) block = new_block;
         if (kDebugStyles) {
-          ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
+          ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType,
+                value.data);
         }
       }
     }
@@ -165,19 +184,21 @@
     }
 
     if (kDebugStyles) {
-      ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data);
+      ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident,
+            value.dataType, value.data);
     }
 
     // Write the final value back to Java.
     out_values[STYLE_TYPE] = value.dataType;
     out_values[STYLE_DATA] = value.data;
     out_values[STYLE_ASSET_COOKIE] =
-        block != -1 ? static_cast<uint32_t>(res.getTableCookie(block)) : static_cast<uint32_t>(-1);
+        block != -1 ? static_cast<uint32_t>(res.getTableCookie(block))
+                    : static_cast<uint32_t>(-1);
     out_values[STYLE_RESOURCE_ID] = resid;
     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 (out_indices != nullptr && value.dataType != Res_value::TYPE_NULL) {
       indices_idx++;
       out_indices[indices_idx] = ii;
     }
@@ -187,18 +208,18 @@
 
   res.unlock();
 
-  if (out_indices != NULL) {
+  if (out_indices != nullptr) {
     out_indices[0] = indices_idx;
   }
   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);
+    ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p",
+          theme, def_style_attr, def_style_res, xml_parser);
   }
 
   const ResTable& res = theme->getResTable();
@@ -211,7 +232,8 @@
   uint32_t def_style_bag_type_set_flags = 0;
   if (def_style_attr != 0) {
     Res_value value;
-    if (theme->getAttribute(def_style_attr, &value, &def_style_bag_type_set_flags) >= 0) {
+    if (theme->getAttribute(def_style_attr, &value,
+                            &def_style_bag_type_set_flags) >= 0) {
       if (value.dataType == Res_value::TYPE_REFERENCE) {
         def_style_res = value.data;
       }
@@ -221,11 +243,12 @@
   // Retrieve the style class associated with the current XML tag.
   int style = 0;
   uint32_t style_bag_type_set_flags = 0;
-  if (xml_parser != NULL) {
+  if (xml_parser != nullptr) {
     ssize_t idx = xml_parser->indexOfStyle();
     if (idx >= 0 && xml_parser->getAttributeValue(idx, &value) >= 0) {
       if (value.dataType == value.TYPE_ATTRIBUTE) {
-        if (theme->getAttribute(value.data, &value, &style_bag_type_set_flags) < 0) {
+        if (theme->getAttribute(value.data, &value, &style_bag_type_set_flags) <
+            0) {
           value.dataType = Res_value::TYPE_NULL;
         }
       }
@@ -239,29 +262,35 @@
   res.lock();
 
   // Retrieve the default style bag, if requested.
-  const ResTable::bag_entry* def_style_attr_start = NULL;
+  const ResTable::bag_entry* def_style_attr_start = nullptr;
   uint32_t def_style_type_set_flags = 0;
-  ssize_t bag_off =
-      def_style_res != 0
-          ? res.getBagLocked(def_style_res, &def_style_attr_start, &def_style_type_set_flags)
-          : -1;
+  ssize_t bag_off = def_style_res != 0
+                        ? res.getBagLocked(def_style_res, &def_style_attr_start,
+                                           &def_style_type_set_flags)
+                        : -1;
   def_style_type_set_flags |= def_style_bag_type_set_flags;
   const ResTable::bag_entry* const def_style_attr_end =
       def_style_attr_start + (bag_off >= 0 ? bag_off : 0);
-  BagAttributeFinder def_style_attr_finder(def_style_attr_start, def_style_attr_end);
+  BagAttributeFinder def_style_attr_finder(def_style_attr_start,
+                                           def_style_attr_end);
 
   // Retrieve the style class bag, if requested.
-  const ResTable::bag_entry* style_attr_start = NULL;
+  const ResTable::bag_entry* style_attr_start = nullptr;
   uint32_t style_type_set_flags = 0;
-  bag_off = style != 0 ? res.getBagLocked(style, &style_attr_start, &style_type_set_flags) : -1;
+  bag_off =
+      style != 0
+          ? res.getBagLocked(style, &style_attr_start, &style_type_set_flags)
+          : -1;
   style_type_set_flags |= style_bag_type_set_flags;
-  const ResTable::bag_entry* const style_attr_end = style_attr_start + (bag_off >= 0 ? bag_off : 0);
+  const ResTable::bag_entry* const style_attr_end =
+      style_attr_start + (bag_off >= 0 ? bag_off : 0);
   BagAttributeFinder style_attr_finder(style_attr_start, style_attr_end);
 
   // Retrieve the XML attributes, if requested.
   static const ssize_t kXmlBlock = 0x10000000;
   XmlAttributeFinder xml_attr_finder(xml_parser);
-  const size_t xml_attr_end = xml_parser != NULL ? xml_parser->getAttributeCount() : 0;
+  const size_t xml_attr_end =
+      xml_parser != nullptr ? xml_parser->getAttributeCount() : 0;
 
   // Now iterate through all of the attributes that the client has requested,
   // filling in each with whatever data we can find.
@@ -289,34 +318,41 @@
       // We found the attribute we were looking for.
       xml_parser->getAttributeValue(xml_attr_idx, &value);
       if (kDebugStyles) {
-        ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data);
+        ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType,
+              value.data);
       }
     }
 
     if (value.dataType == Res_value::TYPE_NULL) {
-      // Walk through the style class values looking for the requested attribute.
-      const ResTable::bag_entry* const style_attr_entry = style_attr_finder.Find(cur_ident);
+      // Walk through the style class values looking for the requested
+      // attribute.
+      const ResTable::bag_entry* const style_attr_entry =
+          style_attr_finder.Find(cur_ident);
       if (style_attr_entry != style_attr_end) {
         // We found the attribute we were looking for.
         block = style_attr_entry->stringBlock;
         type_set_flags = style_type_set_flags;
         value = style_attr_entry->map.value;
         if (kDebugStyles) {
-          ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data);
+          ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType,
+                value.data);
         }
       }
     }
 
     if (value.dataType == Res_value::TYPE_NULL) {
-      // Walk through the default style values looking for the requested attribute.
-      const ResTable::bag_entry* const def_style_attr_entry = def_style_attr_finder.Find(cur_ident);
+      // Walk through the default style values looking for the requested
+      // attribute.
+      const ResTable::bag_entry* const def_style_attr_entry =
+          def_style_attr_finder.Find(cur_ident);
       if (def_style_attr_entry != def_style_attr_end) {
         // We found the attribute we were looking for.
         block = def_style_attr_entry->stringBlock;
         type_set_flags = style_type_set_flags;
         value = def_style_attr_entry->map.value;
         if (kDebugStyles) {
-          ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
+          ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType,
+                value.data);
         }
       }
     }
@@ -324,30 +360,35 @@
     uint32_t resid = 0;
     if (value.dataType != Res_value::TYPE_NULL) {
       // Take care of resolving the found resource to its final value.
-      ssize_t new_block =
-          theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config);
+      ssize_t new_block = theme->resolveAttributeReference(
+          &value, block, &resid, &type_set_flags, &config);
       if (new_block >= 0) {
         block = new_block;
       }
 
       if (kDebugStyles) {
-        ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
+        ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType,
+              value.data);
       }
     } else {
       // If we still don't have a value for this attribute, try to find
       // it in the theme!
-      ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags);
+      ssize_t new_block =
+          theme->getAttribute(cur_ident, &value, &type_set_flags);
       if (new_block >= 0) {
         if (kDebugStyles) {
-          ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
+          ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType,
+                value.data);
         }
-        new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config);
+        new_block = res.resolveReference(&value, new_block, &resid,
+                                         &type_set_flags, &config);
         if (new_block >= 0) {
           block = new_block;
         }
 
         if (kDebugStyles) {
-          ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
+          ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType,
+                value.data);
         }
       }
     }
@@ -363,20 +404,21 @@
     }
 
     if (kDebugStyles) {
-      ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data);
+      ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident,
+            value.dataType, value.data);
     }
 
     // Write the final value back to Java.
     out_values[STYLE_TYPE] = value.dataType;
     out_values[STYLE_DATA] = value.data;
-    out_values[STYLE_ASSET_COOKIE] = block != kXmlBlock
-                                         ? static_cast<uint32_t>(res.getTableCookie(block))
-                                         : static_cast<uint32_t>(-1);
+    out_values[STYLE_ASSET_COOKIE] =
+        block != kXmlBlock ? static_cast<uint32_t>(res.getTableCookie(block))
+                           : static_cast<uint32_t>(-1);
     out_values[STYLE_RESOURCE_ID] = resid;
     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 (out_indices != nullptr && value.dataType != Res_value::TYPE_NULL) {
       indices_idx++;
       out_indices[indices_idx] = ii;
     }
@@ -386,14 +428,14 @@
 
   res.unlock();
 
-  if (out_indices != NULL) {
+  if (out_indices != nullptr) {
     out_indices[0] = indices_idx;
   }
-  return true;
 }
 
-bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser, 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) {
   ResTable_config config;
   Res_value value;
 
@@ -437,7 +479,8 @@
     if (value.dataType != Res_value::TYPE_NULL) {
       // Take care of resolving the found resource to its final value.
       // printf("Resolving attribute reference\n");
-      ssize_t new_block = res->resolveReference(&value, block, &resid, &type_set_flags, &config);
+      ssize_t new_block = res->resolveReference(&value, block, &resid,
+                                                &type_set_flags, &config);
       if (new_block >= 0) block = new_block;
     }
 
@@ -451,14 +494,14 @@
     // Write the final value back to Java.
     out_values[STYLE_TYPE] = value.dataType;
     out_values[STYLE_DATA] = value.data;
-    out_values[STYLE_ASSET_COOKIE] = block != kXmlBlock
-                                         ? static_cast<uint32_t>(res->getTableCookie(block))
-                                         : static_cast<uint32_t>(-1);
+    out_values[STYLE_ASSET_COOKIE] =
+        block != kXmlBlock ? static_cast<uint32_t>(res->getTableCookie(block))
+                           : static_cast<uint32_t>(-1);
     out_values[STYLE_RESOURCE_ID] = resid;
     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 (out_indices != nullptr && value.dataType != Res_value::TYPE_NULL) {
       indices_idx++;
       out_indices[indices_idx] = ii;
     }
@@ -468,7 +511,7 @@
 
   res->unlock();
 
-  if (out_indices != NULL) {
+  if (out_indices != nullptr) {
     out_indices[0] = indices_idx;
   }
   return true;
diff --git a/libs/androidfw/AttributeFinder.h b/libs/androidfw/include/androidfw/AttributeFinder.h
similarity index 100%
rename from libs/androidfw/AttributeFinder.h
rename to libs/androidfw/include/androidfw/AttributeFinder.h
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..d91a133 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -24,10 +24,12 @@
     AppAsLib_test.cpp \
     Asset_test.cpp \
     AttributeFinder_test.cpp \
+    AttributeResolution_test.cpp \
     ByteBucketArray_test.cpp \
     Config_test.cpp \
     ConfigLocale_test.cpp \
     Idmap_test.cpp \
+    Main.cpp \
     ResTable_test.cpp \
     Split_test.cpp \
     TestHelpers.cpp \
@@ -52,7 +54,7 @@
 
 LOCAL_MODULE := libandroidfw_tests
 LOCAL_CFLAGS := $(androidfw_test_cflags)
-LOCAL_SRC_FILES := $(testFiles) AttributeResolution_test.cpp
+LOCAL_SRC_FILES := $(testFiles)
 LOCAL_STATIC_LIBRARIES := \
     libandroidfw \
     libbase \
@@ -60,6 +62,8 @@
     libcutils \
     liblog \
     libz \
+    libziparchive
+LOCAL_PICKUP_FILES := $(LOCAL_PATH)/data
 
 include $(BUILD_HOST_NATIVE_TEST)
 
@@ -81,6 +85,8 @@
     libcutils \
     libutils \
     libui \
+    libziparchive 
+LOCAL_PICKUP_FILES := $(LOCAL_PATH)/data
 
 include $(BUILD_NATIVE_TEST)
 endif # Not SDK_ONLY
diff --git a/libs/androidfw/tests/AppAsLib_test.cpp b/libs/androidfw/tests/AppAsLib_test.cpp
index 8489acf..ddaa46d 100644
--- a/libs/androidfw/tests/AppAsLib_test.cpp
+++ b/libs/androidfw/tests/AppAsLib_test.cpp
@@ -14,55 +14,69 @@
  * limitations under the License.
  */
 
-#include <androidfw/ResourceTypes.h>
+#include "androidfw/ResourceTypes.h"
 
+#include "TestHelpers.h"
 #include "data/appaslib/R.h"
 
-#include <gtest/gtest.h>
+namespace app = com::android::appaslib::app;
+namespace lib = com::android::appaslib::lib;
 
-using namespace android;
-
-namespace {
-
-#include "data/appaslib/appaslib_arsc.h"
-#include "data/appaslib/appaslib_lib_arsc.h"
+namespace android {
 
 // This tests the app resources loaded as app.
-TEST(AppAsLibTest, loadedAsApp) {
+TEST(AppAsLibTest, LoadedAsApp) {
+  std::string contents;
+  ASSERT_TRUE(
+      ReadFileFromZipToString(GetTestDataPath() + "/appaslib/appaslib.apk",
+                              "resources.arsc", &contents));
+
   ResTable table;
-  ASSERT_EQ(NO_ERROR, table.add(appaslib_arsc, appaslib_arsc_len));
+  ASSERT_EQ(NO_ERROR, table.add(contents.data(), contents.size()));
 
   Res_value val;
-  ssize_t block = table.getResource(appaslib::R::app::integer::number1, &val);
+  ssize_t block = table.getResource(app::R::integer::number1, &val);
   ASSERT_GE(block, 0);
   ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
-  ASSERT_EQ(appaslib::R::app::array::integerArray1, val.data);
+  ASSERT_EQ(app::R::array::integerArray1, val.data);
 }
 
 // This tests the app resources loaded as shared-lib.
-TEST(AppAsLibTest, loadedAsSharedLib) {
+TEST(AppAsLibTest, LoadedAsSharedLib) {
+  std::string contents;
+  ASSERT_TRUE(
+      ReadFileFromZipToString(GetTestDataPath() + "/appaslib/appaslib.apk",
+                              "resources.arsc", &contents));
+
   ResTable table;
   // Load as shared library.
-  ASSERT_EQ(NO_ERROR, table.add(appaslib_arsc, appaslib_arsc_len, NULL, 0, -1, false, true));
+  ASSERT_EQ(NO_ERROR, table.add(contents.data(), contents.size(), NULL, 0, -1,
+                                false, true));
 
   Res_value val;
-  ssize_t block = table.getResource(appaslib::R::lib::integer::number1, &val);
+  ssize_t block = table.getResource(lib::R::integer::number1, &val);
   ASSERT_GE(block, 0);
   ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
-  ASSERT_EQ(appaslib::R::lib::array::integerArray1, val.data);
+  ASSERT_EQ(lib::R::array::integerArray1, val.data);
 }
 
 // This tests the shared-lib loaded with appAsLib as true.
-TEST(AppAsLibTest, loadedSharedLib) {
+TEST(AppAsLibTest, LoadedSharedLib) {
+  std::string contents;
+  ASSERT_TRUE(
+      ReadFileFromZipToString(GetTestDataPath() + "/appaslib/appaslib_lib.apk",
+                              "resources.arsc", &contents));
+
   ResTable table;
   // Load shared library with appAsLib as true.
-  ASSERT_EQ(NO_ERROR, table.add(appaslib_lib_arsc, appaslib_lib_arsc_len, NULL, 0, -1, false, true));
+  ASSERT_EQ(NO_ERROR, table.add(contents.data(), contents.size(), NULL, 0, -1,
+                                false, true));
 
   Res_value val;
-  ssize_t block = table.getResource(appaslib::R::lib::integer::number1, &val);
+  ssize_t block = table.getResource(lib::R::integer::number1, &val);
   ASSERT_GE(block, 0);
   ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
-  ASSERT_EQ(appaslib::R::lib::array::integerArray1, val.data);
+  ASSERT_EQ(lib::R::array::integerArray1, val.data);
 }
 
-}
+}  // namespace android
diff --git a/libs/androidfw/tests/Asset_test.cpp b/libs/androidfw/tests/Asset_test.cpp
index 45c8cef..5018218 100644
--- a/libs/androidfw/tests/Asset_test.cpp
+++ b/libs/androidfw/tests/Asset_test.cpp
@@ -14,24 +14,26 @@
  * limitations under the License.
  */
 
-#include <androidfw/Asset.h>
+#include "androidfw/Asset.h"
 
-#include <gtest/gtest.h>
+#include "gtest/gtest.h"
 
-using namespace android;
+namespace android {
 
 TEST(AssetTest, FileAssetRegistersItself) {
-    const int32_t count = Asset::getGlobalCount();
-    Asset* asset = new _FileAsset();
-    EXPECT_EQ(count + 1, Asset::getGlobalCount());
-    delete asset;
-    EXPECT_EQ(count, Asset::getGlobalCount());
+  const int32_t count = Asset::getGlobalCount();
+  Asset* asset = new _FileAsset();
+  EXPECT_EQ(count + 1, Asset::getGlobalCount());
+  delete asset;
+  EXPECT_EQ(count, Asset::getGlobalCount());
 }
 
 TEST(AssetTest, CompressedAssetRegistersItself) {
-    const int32_t count = Asset::getGlobalCount();
-    Asset* asset = new _CompressedAsset();
-    EXPECT_EQ(count + 1, Asset::getGlobalCount());
-    delete asset;
-    EXPECT_EQ(count, Asset::getGlobalCount());
+  const int32_t count = Asset::getGlobalCount();
+  Asset* asset = new _CompressedAsset();
+  EXPECT_EQ(count + 1, Asset::getGlobalCount());
+  delete asset;
+  EXPECT_EQ(count, Asset::getGlobalCount());
 }
+
+}  // nameapce android
diff --git a/libs/androidfw/tests/AttributeFinder_test.cpp b/libs/androidfw/tests/AttributeFinder_test.cpp
index d9ed48e..7264b81 100644
--- a/libs/androidfw/tests/AttributeFinder_test.cpp
+++ b/libs/androidfw/tests/AttributeFinder_test.cpp
@@ -14,16 +14,18 @@
  * limitations under the License.
  */
 
-#include "../AttributeFinder.h"
+#include "androidfw/AttributeFinder.h"
 
-#include <android-base/macros.h>
-#include <gtest/gtest.h>
+#include "android-base/macros.h"
+#include "gtest/gtest.h"
 
-using android::BackTrackingAttributeFinder;
+namespace android {
 
-class MockAttributeFinder : public BackTrackingAttributeFinder<MockAttributeFinder, int> {
+class MockAttributeFinder
+    : public BackTrackingAttributeFinder<MockAttributeFinder, int> {
  public:
-  MockAttributeFinder(const uint32_t* attrs, int len) : BackTrackingAttributeFinder(0, len) {
+  MockAttributeFinder(const uint32_t* attrs, int len)
+      : BackTrackingAttributeFinder(0, len) {
     attrs_ = new uint32_t[len];
     memcpy(attrs_, attrs, sizeof(*attrs) * len);
   }
@@ -36,13 +38,16 @@
   uint32_t* attrs_;
 };
 
-static const uint32_t kSortedAttributes[] = {0x01010000, 0x01010001, 0x01010002, 0x01010004,
-                                             0x02010001, 0x02010010, 0x7f010001};
+static const uint32_t kSortedAttributes[] = {0x01010000, 0x01010001, 0x01010002,
+                                             0x01010004, 0x02010001, 0x02010010,
+                                             0x7f010001};
 
 static const uint32_t kPackageUnsortedAttributes[] = {
-    0x02010001, 0x02010010, 0x01010000, 0x01010001, 0x01010002, 0x01010004, 0x7f010001};
+    0x02010001, 0x02010010, 0x01010000, 0x01010001,
+    0x01010002, 0x01010004, 0x7f010001};
 
-static const uint32_t kSinglePackageAttributes[] = {0x7f010007, 0x7f01000a, 0x7f01000d, 0x00000000};
+static const uint32_t kSinglePackageAttributes[] = {0x7f010007, 0x7f01000a,
+                                                    0x7f01000d, 0x00000000};
 
 TEST(AttributeFinderTest, IteratesSequentially) {
   const int end = arraysize(kSortedAttributes);
@@ -116,3 +121,5 @@
   EXPECT_EQ(end, finder.Find(0x010100fa));
   EXPECT_EQ(0, finder.Find(0x7f010007));
 }
+
+}  // namespace android
diff --git a/libs/androidfw/tests/AttributeResolution_test.cpp b/libs/androidfw/tests/AttributeResolution_test.cpp
index 7fbe6d3..d417aba 100644
--- a/libs/androidfw/tests/AttributeResolution_test.cpp
+++ b/libs/androidfw/tests/AttributeResolution_test.cpp
@@ -15,24 +15,26 @@
  */
 
 #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 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);
+    ASSERT_TRUE(ReadFileFromZipToString(
+        GetTestDataPath() + "/styles/styles.apk", "resources.arsc", &contents));
+    ASSERT_EQ(NO_ERROR, table_.add(contents.data(), contents.size(),
+                                   1 /*cookie*/, true /*copyData*/));
   }
 
  protected:
@@ -43,11 +45,14 @@
  public:
   virtual void SetUp() override {
     AttributeResolutionTest::SetUp();
-    std::string test_source_dir = TestSourceDir();
+
     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);
+    ASSERT_TRUE(
+        ReadFileFromZipToString(GetTestDataPath() + "/styles/styles.apk",
+                                "res/layout/layout.xml", &contents));
+
+    ASSERT_EQ(NO_ERROR, xml_parser_.setTo(contents.data(), contents.size(),
+                                          true /*copyData*/));
 
     // Skip to the first tag.
     while (xml_parser_.next() != ResXMLParser::START_TAG) {
@@ -68,8 +73,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 +117,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 +157,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 +206,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/ByteBucketArray_test.cpp b/libs/androidfw/tests/ByteBucketArray_test.cpp
index 376e79c..5d464c7 100644
--- a/libs/androidfw/tests/ByteBucketArray_test.cpp
+++ b/libs/androidfw/tests/ByteBucketArray_test.cpp
@@ -14,28 +14,42 @@
  * limitations under the License.
  */
 
-#include <androidfw/ByteBucketArray.h>
+#include "androidfw/ByteBucketArray.h"
 
-#include <gtest/gtest.h>
+#include "gtest/gtest.h"
 
-using android::ByteBucketArray;
+namespace android {
 
 TEST(ByteBucketArrayTest, TestSparseInsertion) {
-    ByteBucketArray<int> bba;
-    ASSERT_TRUE(bba.set(0, 1));
-    ASSERT_TRUE(bba.set(10, 2));
-    ASSERT_TRUE(bba.set(26, 3));
-    ASSERT_TRUE(bba.set(129, 4));
-    ASSERT_TRUE(bba.set(234, 5));
+  ByteBucketArray<int> bba;
+  ASSERT_TRUE(bba.set(0, 1));
+  ASSERT_TRUE(bba.set(10, 2));
+  ASSERT_TRUE(bba.set(26, 3));
+  ASSERT_TRUE(bba.set(129, 4));
+  ASSERT_TRUE(bba.set(234, 5));
 
-    for (size_t i = 0; i < bba.size(); i++) {
-        switch (i) {
-            case 0: EXPECT_EQ(1, bba[i]); break;
-            case 10: EXPECT_EQ(2, bba[i]); break;
-            case 26: EXPECT_EQ(3, bba[i]); break;
-            case 129: EXPECT_EQ(4, bba[i]); break;
-            case 234: EXPECT_EQ(5, bba[i]); break;
-            default: EXPECT_EQ(0, bba[i]); break;
-        }
+  for (size_t i = 0; i < bba.size(); i++) {
+    switch (i) {
+      case 0:
+        EXPECT_EQ(1, bba[i]);
+        break;
+      case 10:
+        EXPECT_EQ(2, bba[i]);
+        break;
+      case 26:
+        EXPECT_EQ(3, bba[i]);
+        break;
+      case 129:
+        EXPECT_EQ(4, bba[i]);
+        break;
+      case 234:
+        EXPECT_EQ(5, bba[i]);
+        break;
+      default:
+        EXPECT_EQ(0, bba[i]);
+        break;
     }
+  }
 }
+
+}  // namespace android
diff --git a/libs/androidfw/tests/Config_test.cpp b/libs/androidfw/tests/Config_test.cpp
index 738947a..778c7bf 100644
--- a/libs/androidfw/tests/Config_test.cpp
+++ b/libs/androidfw/tests/Config_test.cpp
@@ -14,168 +14,172 @@
  * limitations under the License.
  */
 
-#include <androidfw/ResourceTypes.h>
-#include <utils/Log.h>
-#include <utils/String8.h>
-#include <utils/Vector.h>
+#include "androidfw/ResourceTypes.h"
+
+#include "utils/Log.h"
+#include "utils/String8.h"
+#include "utils/Vector.h"
 
 #include "TestHelpers.h"
-#include <gtest/gtest.h>
+#include "gtest/gtest.h"
 
 namespace android {
 
 static ResTable_config selectBest(const ResTable_config& target,
-        const Vector<ResTable_config>& configs) {
-    ResTable_config bestConfig;
-    memset(&bestConfig, 0, sizeof(bestConfig));
-    const size_t configCount = configs.size();
-    for (size_t i = 0; i < configCount; i++) {
-        const ResTable_config& thisConfig = configs[i];
-        if (!thisConfig.match(target)) {
-            continue;
-        }
-
-        if (thisConfig.isBetterThan(bestConfig, &target)) {
-            bestConfig = thisConfig;
-        }
+                                  const Vector<ResTable_config>& configs) {
+  ResTable_config bestConfig;
+  memset(&bestConfig, 0, sizeof(bestConfig));
+  const size_t configCount = configs.size();
+  for (size_t i = 0; i < configCount; i++) {
+    const ResTable_config& thisConfig = configs[i];
+    if (!thisConfig.match(target)) {
+      continue;
     }
-    return bestConfig;
+
+    if (thisConfig.isBetterThan(bestConfig, &target)) {
+      bestConfig = thisConfig;
+    }
+  }
+  return bestConfig;
 }
 
 static ResTable_config buildDensityConfig(int density) {
-    ResTable_config config;
-    memset(&config, 0, sizeof(config));
-    config.density = uint16_t(density);
-    config.sdkVersion = 4;
-    return config;
+  ResTable_config config;
+  memset(&config, 0, sizeof(config));
+  config.density = uint16_t(density);
+  config.sdkVersion = 4;
+  return config;
 }
 
 TEST(ConfigTest, shouldSelectBestDensity) {
-    ResTable_config deviceConfig;
-    memset(&deviceConfig, 0, sizeof(deviceConfig));
-    deviceConfig.density = ResTable_config::DENSITY_XHIGH;
-    deviceConfig.sdkVersion = 21;
+  ResTable_config deviceConfig;
+  memset(&deviceConfig, 0, sizeof(deviceConfig));
+  deviceConfig.density = ResTable_config::DENSITY_XHIGH;
+  deviceConfig.sdkVersion = 21;
 
-    Vector<ResTable_config> configs;
+  Vector<ResTable_config> configs;
 
-    ResTable_config expectedBest = buildDensityConfig(ResTable_config::DENSITY_HIGH);
-    configs.add(expectedBest);
-    ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));
+  ResTable_config expectedBest =
+      buildDensityConfig(ResTable_config::DENSITY_HIGH);
+  configs.add(expectedBest);
+  ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));
 
-    expectedBest = buildDensityConfig(ResTable_config::DENSITY_XXHIGH);
-    configs.add(expectedBest);
-    ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));
+  expectedBest = buildDensityConfig(ResTable_config::DENSITY_XXHIGH);
+  configs.add(expectedBest);
+  ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));
 
-    expectedBest = buildDensityConfig(int(ResTable_config::DENSITY_XXHIGH) - 20);
-    configs.add(expectedBest);
-    ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));
+  expectedBest = buildDensityConfig(int(ResTable_config::DENSITY_XXHIGH) - 20);
+  configs.add(expectedBest);
+  ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));
 
-    configs.add(buildDensityConfig(int(ResTable_config::DENSITY_HIGH) + 20));
-    ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));
+  configs.add(buildDensityConfig(int(ResTable_config::DENSITY_HIGH) + 20));
+  ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));
 
-    expectedBest = buildDensityConfig(ResTable_config::DENSITY_XHIGH);
-    configs.add(expectedBest);
-    ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));
+  expectedBest = buildDensityConfig(ResTable_config::DENSITY_XHIGH);
+  configs.add(expectedBest);
+  ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));
 
-    expectedBest = buildDensityConfig(ResTable_config::DENSITY_ANY);
-    expectedBest.sdkVersion = 21;
-    configs.add(expectedBest);
-    ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));
+  expectedBest = buildDensityConfig(ResTable_config::DENSITY_ANY);
+  expectedBest.sdkVersion = 21;
+  configs.add(expectedBest);
+  ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));
 }
 
 TEST(ConfigTest, shouldSelectBestDensityWhenNoneSpecified) {
-    ResTable_config deviceConfig;
-    memset(&deviceConfig, 0, sizeof(deviceConfig));
-    deviceConfig.sdkVersion = 21;
+  ResTable_config deviceConfig;
+  memset(&deviceConfig, 0, sizeof(deviceConfig));
+  deviceConfig.sdkVersion = 21;
 
-    Vector<ResTable_config> configs;
-    configs.add(buildDensityConfig(ResTable_config::DENSITY_HIGH));
+  Vector<ResTable_config> configs;
+  configs.add(buildDensityConfig(ResTable_config::DENSITY_HIGH));
 
-    ResTable_config expectedBest = buildDensityConfig(ResTable_config::DENSITY_MEDIUM);
-    configs.add(expectedBest);
-    ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));
+  ResTable_config expectedBest =
+      buildDensityConfig(ResTable_config::DENSITY_MEDIUM);
+  configs.add(expectedBest);
+  ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));
 
-    expectedBest = buildDensityConfig(ResTable_config::DENSITY_ANY);
-    configs.add(expectedBest);
-    ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));
+  expectedBest = buildDensityConfig(ResTable_config::DENSITY_ANY);
+  configs.add(expectedBest);
+  ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));
 }
 
 TEST(ConfigTest, shouldMatchRoundQualifier) {
-    ResTable_config deviceConfig;
-    memset(&deviceConfig, 0, sizeof(deviceConfig));
+  ResTable_config deviceConfig;
+  memset(&deviceConfig, 0, sizeof(deviceConfig));
 
-    ResTable_config roundConfig;
-    memset(&roundConfig, 0, sizeof(roundConfig));
-    roundConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;
+  ResTable_config roundConfig;
+  memset(&roundConfig, 0, sizeof(roundConfig));
+  roundConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;
 
-    EXPECT_FALSE(roundConfig.match(deviceConfig));
+  EXPECT_FALSE(roundConfig.match(deviceConfig));
 
-    deviceConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;
+  deviceConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;
 
-    EXPECT_TRUE(roundConfig.match(deviceConfig));
+  EXPECT_TRUE(roundConfig.match(deviceConfig));
 
-    deviceConfig.screenLayout2 = ResTable_config::SCREENROUND_NO;
+  deviceConfig.screenLayout2 = ResTable_config::SCREENROUND_NO;
 
-    EXPECT_FALSE(roundConfig.match(deviceConfig));
+  EXPECT_FALSE(roundConfig.match(deviceConfig));
 
-    ResTable_config notRoundConfig;
-    memset(&notRoundConfig, 0, sizeof(notRoundConfig));
-    notRoundConfig.screenLayout2 = ResTable_config::SCREENROUND_NO;
+  ResTable_config notRoundConfig;
+  memset(&notRoundConfig, 0, sizeof(notRoundConfig));
+  notRoundConfig.screenLayout2 = ResTable_config::SCREENROUND_NO;
 
-    EXPECT_TRUE(notRoundConfig.match(deviceConfig));
+  EXPECT_TRUE(notRoundConfig.match(deviceConfig));
 }
 
 TEST(ConfigTest, RoundQualifierShouldHaveStableSortOrder) {
-    ResTable_config defaultConfig;
-    memset(&defaultConfig, 0, sizeof(defaultConfig));
+  ResTable_config defaultConfig;
+  memset(&defaultConfig, 0, sizeof(defaultConfig));
 
-    ResTable_config longConfig = defaultConfig;
-    longConfig.screenLayout = ResTable_config::SCREENLONG_YES;
+  ResTable_config longConfig = defaultConfig;
+  longConfig.screenLayout = ResTable_config::SCREENLONG_YES;
 
-    ResTable_config longRoundConfig = longConfig;
-    longRoundConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;
+  ResTable_config longRoundConfig = longConfig;
+  longRoundConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;
 
-    ResTable_config longRoundPortConfig = longConfig;
-    longRoundPortConfig.orientation = ResTable_config::ORIENTATION_PORT;
+  ResTable_config longRoundPortConfig = longConfig;
+  longRoundPortConfig.orientation = ResTable_config::ORIENTATION_PORT;
 
-    EXPECT_TRUE(longConfig.compare(longRoundConfig) < 0);
-    EXPECT_TRUE(longConfig.compareLogical(longRoundConfig) < 0);
-    EXPECT_TRUE(longRoundConfig.compare(longConfig) > 0);
-    EXPECT_TRUE(longRoundConfig.compareLogical(longConfig) > 0);
+  EXPECT_TRUE(longConfig.compare(longRoundConfig) < 0);
+  EXPECT_TRUE(longConfig.compareLogical(longRoundConfig) < 0);
+  EXPECT_TRUE(longRoundConfig.compare(longConfig) > 0);
+  EXPECT_TRUE(longRoundConfig.compareLogical(longConfig) > 0);
 
-    EXPECT_TRUE(longRoundConfig.compare(longRoundPortConfig) < 0);
-    EXPECT_TRUE(longRoundConfig.compareLogical(longRoundPortConfig) < 0);
-    EXPECT_TRUE(longRoundPortConfig.compare(longRoundConfig) > 0);
-    EXPECT_TRUE(longRoundPortConfig.compareLogical(longRoundConfig) > 0);
+  EXPECT_TRUE(longRoundConfig.compare(longRoundPortConfig) < 0);
+  EXPECT_TRUE(longRoundConfig.compareLogical(longRoundPortConfig) < 0);
+  EXPECT_TRUE(longRoundPortConfig.compare(longRoundConfig) > 0);
+  EXPECT_TRUE(longRoundPortConfig.compareLogical(longRoundConfig) > 0);
 }
 
 TEST(ConfigTest, ScreenShapeHasCorrectDiff) {
-    ResTable_config defaultConfig;
-    memset(&defaultConfig, 0, sizeof(defaultConfig));
+  ResTable_config defaultConfig;
+  memset(&defaultConfig, 0, sizeof(defaultConfig));
 
-    ResTable_config roundConfig = defaultConfig;
-    roundConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;
+  ResTable_config roundConfig = defaultConfig;
+  roundConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;
 
-    EXPECT_EQ(defaultConfig.diff(roundConfig), ResTable_config::CONFIG_SCREEN_ROUND);
+  EXPECT_EQ(defaultConfig.diff(roundConfig),
+            ResTable_config::CONFIG_SCREEN_ROUND);
 }
 
 TEST(ConfigTest, RoundIsMoreSpecific) {
-    ResTable_config deviceConfig;
-    memset(&deviceConfig, 0, sizeof(deviceConfig));
-    deviceConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;
-    deviceConfig.screenLayout = ResTable_config::SCREENLONG_YES;
+  ResTable_config deviceConfig;
+  memset(&deviceConfig, 0, sizeof(deviceConfig));
+  deviceConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;
+  deviceConfig.screenLayout = ResTable_config::SCREENLONG_YES;
 
-    ResTable_config targetConfigA;
-    memset(&targetConfigA, 0, sizeof(targetConfigA));
+  ResTable_config targetConfigA;
+  memset(&targetConfigA, 0, sizeof(targetConfigA));
 
-    ResTable_config targetConfigB = targetConfigA;
-    targetConfigB.screenLayout = ResTable_config::SCREENLONG_YES;
+  ResTable_config targetConfigB = targetConfigA;
+  targetConfigB.screenLayout = ResTable_config::SCREENLONG_YES;
 
-    ResTable_config targetConfigC = targetConfigB;
-    targetConfigC.screenLayout2 = ResTable_config::SCREENROUND_YES;
+  ResTable_config targetConfigC = targetConfigB;
+  targetConfigC.screenLayout2 = ResTable_config::SCREENROUND_YES;
 
-    EXPECT_TRUE(targetConfigB.isBetterThan(targetConfigA, &deviceConfig));
-    EXPECT_TRUE(targetConfigC.isBetterThan(targetConfigB, &deviceConfig));
+  EXPECT_TRUE(targetConfigB.isBetterThan(targetConfigA, &deviceConfig));
+  EXPECT_TRUE(targetConfigC.isBetterThan(targetConfigB, &deviceConfig));
 }
 
 }  // namespace android.
diff --git a/libs/androidfw/tests/Idmap_test.cpp b/libs/androidfw/tests/Idmap_test.cpp
index f50c178..0928b1b 100644
--- a/libs/androidfw/tests/Idmap_test.cpp
+++ b/libs/androidfw/tests/Idmap_test.cpp
@@ -14,102 +14,102 @@
  * limitations under the License.
  */
 
-#include <androidfw/ResourceTypes.h>
+#include "androidfw/ResourceTypes.h"
 
-#include <utils/String8.h>
-#include <utils/String16.h>
+#include "utils/String16.h"
+#include "utils/String8.h"
+
 #include "TestHelpers.h"
 #include "data/basic/R.h"
 
-#include <gtest/gtest.h>
+using com::android::basic::R;
 
-using namespace android;
-
-namespace {
-
-/**
- * Include a binary resource table.
- *
- * Package: com.android.test.basic
- */
-#include "data/basic/basic_arsc.h"
-
-/**
- * Include a binary resource table.
- * This table is an overlay.
- *
- * Package: com.android.test.basic
- */
-#include "data/overlay/overlay_arsc.h"
-
-enum { MAY_NOT_BE_BAG = false };
+namespace android {
 
 class IdmapTest : public ::testing::Test {
-protected:
-    virtual void SetUp() {
-        ASSERT_EQ(NO_ERROR, mTargetTable.add(basic_arsc, basic_arsc_len));
-        ASSERT_EQ(NO_ERROR, mOverlayTable.add(overlay_arsc, overlay_arsc_len));
-        char targetName[256] = "com.android.test.basic";
-        ASSERT_EQ(NO_ERROR, mTargetTable.createIdmap(mOverlayTable, 0, 0,
-                    targetName, targetName, &mData, &mDataSize));
-    }
+ protected:
+  void SetUp() override {
+    std::string contents;
+    ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk",
+                                        "resources.arsc", &contents));
+    ASSERT_EQ(NO_ERROR,
+              target_table_.add(contents.data(), contents.size(), 0, true));
 
-    virtual void TearDown() {
-        free(mData);
-    }
+    ASSERT_TRUE(
+        ReadFileFromZipToString(GetTestDataPath() + "/overlay/overlay.apk",
+                                "resources.arsc", &overlay_data_));
+    ResTable overlay_table;
+    ASSERT_EQ(NO_ERROR,
+              overlay_table.add(overlay_data_.data(), overlay_data_.size()));
 
-    ResTable mTargetTable;
-    ResTable mOverlayTable;
-    void* mData;
-    size_t mDataSize;
+    char target_name[256] = "com.android.basic";
+    ASSERT_EQ(NO_ERROR,
+              target_table_.createIdmap(overlay_table, 0, 0, target_name,
+                                        target_name, &data_, &data_size_));
+  }
+
+  void TearDown() override { ::free(data_); }
+
+  ResTable target_table_;
+  std::string overlay_data_;
+  void* data_ = nullptr;
+  size_t data_size_ = 0;
 };
 
 TEST_F(IdmapTest, canLoadIdmap) {
-    ASSERT_EQ(NO_ERROR, mTargetTable.add(overlay_arsc, overlay_arsc_len, mData, mDataSize));
+  ASSERT_EQ(NO_ERROR,
+            target_table_.add(overlay_data_.data(), overlay_data_.size(), data_,
+                              data_size_));
 }
 
 TEST_F(IdmapTest, overlayOverridesResourceValue) {
-    Res_value val;
-    ssize_t block = mTargetTable.getResource(base::R::string::test2, &val, false);
-    ASSERT_GE(block, 0);
-    ASSERT_EQ(Res_value::TYPE_STRING, val.dataType);
-    const ResStringPool* pool = mTargetTable.getTableStringBlock(block);
-    ASSERT_TRUE(pool != NULL);
-    ASSERT_LT(val.data, pool->size());
+  Res_value val;
+  ssize_t block = target_table_.getResource(R::string::test2, &val, false);
+  ASSERT_GE(block, 0);
+  ASSERT_EQ(Res_value::TYPE_STRING, val.dataType);
+  const ResStringPool* pool = target_table_.getTableStringBlock(block);
+  ASSERT_TRUE(pool != NULL);
+  ASSERT_LT(val.data, pool->size());
 
-    size_t strLen;
-    const char16_t* targetStr16 = pool->stringAt(val.data, &strLen);
-    ASSERT_TRUE(targetStr16 != NULL);
-    ASSERT_EQ(String16("test2"), String16(targetStr16, strLen));
+  size_t strLen;
+  const char16_t* targetStr16 = pool->stringAt(val.data, &strLen);
+  ASSERT_TRUE(targetStr16 != NULL);
+  ASSERT_EQ(String16("test2"), String16(targetStr16, strLen));
 
-    ASSERT_EQ(NO_ERROR, mTargetTable.add(overlay_arsc, overlay_arsc_len, mData, mDataSize));
+  ASSERT_EQ(NO_ERROR,
+            target_table_.add(overlay_data_.data(), overlay_data_.size(), data_,
+                              data_size_));
 
-    ssize_t newBlock = mTargetTable.getResource(base::R::string::test2, &val, false);
-    ASSERT_GE(newBlock, 0);
-    ASSERT_NE(block, newBlock);
-    ASSERT_EQ(Res_value::TYPE_STRING, val.dataType);
-    pool = mTargetTable.getTableStringBlock(newBlock);
-    ASSERT_TRUE(pool != NULL);
-    ASSERT_LT(val.data, pool->size());
+  ssize_t newBlock = target_table_.getResource(R::string::test2, &val, false);
+  ASSERT_GE(newBlock, 0);
+  ASSERT_NE(block, newBlock);
+  ASSERT_EQ(Res_value::TYPE_STRING, val.dataType);
+  pool = target_table_.getTableStringBlock(newBlock);
+  ASSERT_TRUE(pool != NULL);
+  ASSERT_LT(val.data, pool->size());
 
-    targetStr16 = pool->stringAt(val.data, &strLen);
-    ASSERT_TRUE(targetStr16 != NULL);
-    ASSERT_EQ(String16("test2-overlay"), String16(targetStr16, strLen));
+  targetStr16 = pool->stringAt(val.data, &strLen);
+  ASSERT_TRUE(targetStr16 != NULL);
+  ASSERT_EQ(String16("test2-overlay"), String16(targetStr16, strLen));
 }
 
 TEST_F(IdmapTest, overlaidResourceHasSameName) {
-    ASSERT_EQ(NO_ERROR, mTargetTable.add(overlay_arsc, overlay_arsc_len, mData, mDataSize));
+  ASSERT_EQ(NO_ERROR,
+            target_table_.add(overlay_data_.data(), overlay_data_.size(), data_,
+                              data_size_));
 
-    ResTable::resource_name resName;
-    ASSERT_TRUE(mTargetTable.getResourceName(base::R::array::integerArray1, false, &resName));
+  ResTable::resource_name resName;
+  ASSERT_TRUE(
+      target_table_.getResourceName(R::array::integerArray1, false, &resName));
 
-    ASSERT_TRUE(resName.package != NULL);
-    ASSERT_TRUE(resName.type != NULL);
-    ASSERT_TRUE(resName.name != NULL);
+  ASSERT_TRUE(resName.package != NULL);
+  ASSERT_TRUE(resName.type != NULL);
+  ASSERT_TRUE(resName.name != NULL);
 
-    EXPECT_EQ(String16("com.android.test.basic"), String16(resName.package, resName.packageLen));
-    EXPECT_EQ(String16("array"), String16(resName.type, resName.typeLen));
-    EXPECT_EQ(String16("integerArray1"), String16(resName.name, resName.nameLen));
+  EXPECT_EQ(String16("com.android.basic"),
+            String16(resName.package, resName.packageLen));
+  EXPECT_EQ(String16("array"), String16(resName.type, resName.typeLen));
+  EXPECT_EQ(String16("integerArray1"), String16(resName.name, resName.nameLen));
 }
 
-} // namespace
+}  // namespace
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/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp
index 9e53dd2..b151f3f 100644
--- a/libs/androidfw/tests/ResTable_test.cpp
+++ b/libs/androidfw/tests/ResTable_test.cpp
@@ -14,352 +14,386 @@
  * limitations under the License.
  */
 
-#include <androidfw/ResourceTypes.h>
+#include "androidfw/ResourceTypes.h"
 
 #include <codecvt>
 #include <locale>
 #include <string>
 
-#include <utils/String8.h>
-#include <utils/String16.h>
+#include "utils/String16.h"
+#include "utils/String8.h"
+
 #include "TestHelpers.h"
 #include "data/basic/R.h"
 #include "data/lib/R.h"
 
-#include <gtest/gtest.h>
+namespace basic = com::android::basic;
+namespace lib = com::android::lib;
 
-using namespace android;
+namespace android {
 
-namespace {
+TEST(ResTableTest, ShouldLoadSuccessfully) {
+  std::string contents;
+  ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk",
+                                      "resources.arsc", &contents));
 
-/**
- * Include a binary resource table.
- *
- * Package: com.android.test.basic
- */
-#include "data/basic/basic_arsc.h"
-
-/**
- * Include a binary library resource table.
- *
- * Package: com.android.test.basic
- */
-#include "data/lib/lib_arsc.h"
-
-/**
- * Include a system resource table.
- *
- * Package: android
- */
-#include "data/system/system_arsc.h"
-
-TEST(ResTableTest, shouldLoadSuccessfully) {
-    ResTable table;
-    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+  ResTable table;
+  ASSERT_EQ(NO_ERROR, table.add(contents.data(), contents.size()));
 }
 
-TEST(ResTableTest, simpleTypeIsRetrievedCorrectly) {
-    ResTable table;
-    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+TEST(ResTableTest, SimpleTypeIsRetrievedCorrectly) {
+  std::string contents;
+  ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk",
+                                      "resources.arsc", &contents));
 
-    EXPECT_TRUE(IsStringEqual(table, base::R::string::test1, "test1"));
+  ResTable table;
+  ASSERT_EQ(NO_ERROR, table.add(contents.data(), contents.size()));
+
+  EXPECT_TRUE(IsStringEqual(table, basic::R::string::test1, "test1"));
 }
 
-TEST(ResTableTest, resourceNameIsResolved) {
-    ResTable table;
-    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+TEST(ResTableTest, ResourceNameIsResolved) {
+  std::string contents;
+  ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk",
+                                      "resources.arsc", &contents));
 
-    String16 defPackage("com.android.test.basic");
-    String16 testName("@string/test1");
-    uint32_t resID = table.identifierForName(testName.string(), testName.size(),
-                                             0, 0,
-                                             defPackage.string(), defPackage.size());
-    ASSERT_NE(uint32_t(0x00000000), resID);
-    ASSERT_EQ(base::R::string::test1, resID);
+  ResTable table;
+  ASSERT_EQ(NO_ERROR, table.add(contents.data(), contents.size()));
+
+  String16 defPackage("com.android.basic");
+  String16 testName("@string/test1");
+  uint32_t resID =
+      table.identifierForName(testName.string(), testName.size(), 0, 0,
+                              defPackage.string(), defPackage.size());
+  ASSERT_NE(uint32_t(0x00000000), resID);
+  ASSERT_EQ(basic::R::string::test1, resID);
 }
 
-TEST(ResTableTest, noParentThemeIsAppliedCorrectly) {
-    ResTable table;
-    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+TEST(ResTableTest, NoParentThemeIsAppliedCorrectly) {
+  std::string contents;
+  ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk",
+                                      "resources.arsc", &contents));
 
-    ResTable::Theme theme(table);
-    ASSERT_EQ(NO_ERROR, theme.applyStyle(base::R::style::Theme1));
+  ResTable table;
+  ASSERT_EQ(NO_ERROR, table.add(contents.data(), contents.size()));
 
-    Res_value val;
-    uint32_t specFlags = 0;
-    ssize_t index = theme.getAttribute(base::R::attr::attr1, &val, &specFlags);
-    ASSERT_GE(index, 0);
-    ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
-    ASSERT_EQ(uint32_t(100), val.data);
+  ResTable::Theme theme(table);
+  ASSERT_EQ(NO_ERROR, theme.applyStyle(basic::R::style::Theme1));
 
-    index = theme.getAttribute(base::R::attr::attr2, &val, &specFlags);
-    ASSERT_GE(index, 0);
-    ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
-    ASSERT_EQ(base::R::integer::number1, val.data);
+  Res_value val;
+  uint32_t specFlags = 0;
+  ssize_t index = theme.getAttribute(basic::R::attr::attr1, &val, &specFlags);
+  ASSERT_GE(index, 0);
+  ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+  ASSERT_EQ(uint32_t(100), val.data);
+
+  index = theme.getAttribute(basic::R::attr::attr2, &val, &specFlags);
+  ASSERT_GE(index, 0);
+  ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
+  ASSERT_EQ(basic::R::integer::number1, val.data);
 }
 
-TEST(ResTableTest, parentThemeIsAppliedCorrectly) {
-    ResTable table;
-    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+TEST(ResTableTest, ParentThemeIsAppliedCorrectly) {
+  std::string contents;
+  ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk",
+                                      "resources.arsc", &contents));
 
-    ResTable::Theme theme(table);
-    ASSERT_EQ(NO_ERROR, theme.applyStyle(base::R::style::Theme2));
+  ResTable table;
+  ASSERT_EQ(NO_ERROR, table.add(contents.data(), contents.size()));
 
-    Res_value val;
-    uint32_t specFlags = 0;
-    ssize_t index = theme.getAttribute(base::R::attr::attr1, &val, &specFlags);
-    ASSERT_GE(index, 0);
-    ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
-    ASSERT_EQ(uint32_t(300), val.data);
+  ResTable::Theme theme(table);
+  ASSERT_EQ(NO_ERROR, theme.applyStyle(basic::R::style::Theme2));
 
-    index = theme.getAttribute(base::R::attr::attr2, &val, &specFlags);
-    ASSERT_GE(index, 0);
-    ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
-    ASSERT_EQ(base::R::integer::number1, val.data);
+  Res_value val;
+  uint32_t specFlags = 0;
+  ssize_t index = theme.getAttribute(basic::R::attr::attr1, &val, &specFlags);
+  ASSERT_GE(index, 0);
+  ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+  ASSERT_EQ(uint32_t(300), val.data);
+
+  index = theme.getAttribute(basic::R::attr::attr2, &val, &specFlags);
+  ASSERT_GE(index, 0);
+  ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
+  ASSERT_EQ(basic::R::integer::number1, val.data);
 }
 
-TEST(ResTableTest, libraryThemeIsAppliedCorrectly) {
-    ResTable table;
-    ASSERT_EQ(NO_ERROR, table.add(lib_arsc, lib_arsc_len));
+TEST(ResTableTest, LibraryThemeIsAppliedCorrectly) {
+  std::string contents;
+  ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/lib/lib.apk",
+                                      "resources.arsc", &contents));
 
-    ResTable::Theme theme(table);
-    ASSERT_EQ(NO_ERROR, theme.applyStyle(lib::R::style::Theme));
+  ResTable table;
+  ASSERT_EQ(NO_ERROR, table.add(contents.data(), contents.size()));
 
-    Res_value val;
-    uint32_t specFlags = 0;
-    ssize_t index = theme.getAttribute(lib::R::attr::attr1, &val, &specFlags);
-    ASSERT_GE(index, 0);
-    ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
-    ASSERT_EQ(uint32_t(700), val.data);
+  ResTable::Theme theme(table);
+  ASSERT_EQ(NO_ERROR, theme.applyStyle(lib::R::style::Theme));
 
-    index = theme.getAttribute(lib::R::attr::attr2, &val, &specFlags);
-    ASSERT_GE(index, 0);
-    ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
-    ASSERT_EQ(uint32_t(700), val.data);
+  Res_value val;
+  uint32_t specFlags = 0;
+  ssize_t index = theme.getAttribute(lib::R::attr::attr1, &val, &specFlags);
+  ASSERT_GE(index, 0);
+  ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+  ASSERT_EQ(uint32_t(700), val.data);
+
+  index = theme.getAttribute(lib::R::attr::attr2, &val, &specFlags);
+  ASSERT_GE(index, 0);
+  ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+  ASSERT_EQ(uint32_t(700), val.data);
 }
 
-TEST(ResTableTest, referenceToBagIsNotResolved) {
-    ResTable table;
-    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+TEST(ResTableTest, ReferenceToBagIsNotResolved) {
+  std::string contents;
+  ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk",
+                                      "resources.arsc", &contents));
 
-    Res_value val;
-    ssize_t block = table.getResource(base::R::integer::number2, &val, MAY_NOT_BE_BAG);
-    ASSERT_GE(block, 0);
-    ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
-    ASSERT_EQ(base::R::array::integerArray1, val.data);
+  ResTable table;
+  ASSERT_EQ(NO_ERROR, table.add(contents.data(), contents.size()));
 
-    ssize_t newBlock = table.resolveReference(&val, block);
-    EXPECT_EQ(block, newBlock);
-    EXPECT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
-    EXPECT_EQ(base::R::array::integerArray1, val.data);
+  Res_value val;
+  ssize_t block =
+      table.getResource(basic::R::integer::number2, &val, MAY_NOT_BE_BAG);
+  ASSERT_GE(block, 0);
+  ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
+  ASSERT_EQ(basic::R::array::integerArray1, val.data);
+
+  ssize_t newBlock = table.resolveReference(&val, block);
+  EXPECT_EQ(block, newBlock);
+  EXPECT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
+  EXPECT_EQ(basic::R::array::integerArray1, val.data);
 }
 
-TEST(ResTableTest, resourcesStillAccessibleAfterParameterChange) {
-    ResTable table;
-    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+TEST(ResTableTest, ResourcesStillAccessibleAfterParameterChange) {
+  std::string contents;
+  ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk",
+                                      "resources.arsc", &contents));
 
-    Res_value val;
-    ssize_t block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
-    ASSERT_GE(block, 0);
-    ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+  ResTable table;
+  ASSERT_EQ(NO_ERROR, table.add(contents.data(), contents.size()));
 
-    const ResTable::bag_entry* entry;
-    ssize_t count = table.lockBag(base::R::array::integerArray1, &entry);
-    ASSERT_GE(count, 0);
-    table.unlockBag(entry);
+  Res_value val;
+  ssize_t block =
+      table.getResource(basic::R::integer::number1, &val, MAY_NOT_BE_BAG);
+  ASSERT_GE(block, 0);
+  ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
 
-    ResTable_config param;
-    memset(&param, 0, sizeof(param));
-    param.density = 320;
-    table.setParameters(&param);
+  const ResTable::bag_entry* entry;
+  ssize_t count = table.lockBag(basic::R::array::integerArray1, &entry);
+  ASSERT_GE(count, 0);
+  table.unlockBag(entry);
 
-    block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
-    ASSERT_GE(block, 0);
-    ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+  ResTable_config param;
+  memset(&param, 0, sizeof(param));
+  param.density = 320;
+  table.setParameters(&param);
 
-    count = table.lockBag(base::R::array::integerArray1, &entry);
-    ASSERT_GE(count, 0);
-    table.unlockBag(entry);
+  block = table.getResource(basic::R::integer::number1, &val, MAY_NOT_BE_BAG);
+  ASSERT_GE(block, 0);
+  ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+
+  count = table.lockBag(basic::R::array::integerArray1, &entry);
+  ASSERT_GE(count, 0);
+  table.unlockBag(entry);
 }
 
-TEST(ResTableTest, resourceIsOverridenWithBetterConfig) {
-    ResTable table;
-    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+TEST(ResTableTest, ResourceIsOverridenWithBetterConfig) {
+  std::string contents;
+  ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk",
+                                      "resources.arsc", &contents));
 
-    Res_value val;
-    ssize_t block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
-    ASSERT_GE(block, 0);
-    ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
-    ASSERT_EQ(uint32_t(200), val.data);
+  ResTable table;
+  ASSERT_EQ(NO_ERROR, table.add(contents.data(), contents.size()));
 
-    ResTable_config param;
-    memset(&param, 0, sizeof(param));
-    param.language[0] = 's';
-    param.language[1] = 'v';
-    param.country[0] = 'S';
-    param.country[1] = 'E';
-    table.setParameters(&param);
+  Res_value val;
+  ssize_t block =
+      table.getResource(basic::R::integer::number1, &val, MAY_NOT_BE_BAG);
+  ASSERT_GE(block, 0);
+  ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+  ASSERT_EQ(uint32_t(200), val.data);
 
-    block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
-    ASSERT_GE(block, 0);
-    ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
-    ASSERT_EQ(uint32_t(400), val.data);
+  ResTable_config param;
+  memset(&param, 0, sizeof(param));
+  param.language[0] = 's';
+  param.language[1] = 'v';
+  param.country[0] = 'S';
+  param.country[1] = 'E';
+  table.setParameters(&param);
+
+  block = table.getResource(basic::R::integer::number1, &val, MAY_NOT_BE_BAG);
+  ASSERT_GE(block, 0);
+  ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+  ASSERT_EQ(uint32_t(400), val.data);
 }
 
 TEST(ResTableTest, emptyTableHasSensibleDefaults) {
-    const int32_t assetCookie = 1;
+  const int32_t assetCookie = 1;
 
-    ResTable table;
-    ASSERT_EQ(NO_ERROR, table.addEmpty(assetCookie));
+  ResTable table;
+  ASSERT_EQ(NO_ERROR, table.addEmpty(assetCookie));
 
-    // Adding an empty table gives us one table!
-    ASSERT_EQ(uint32_t(1), table.getTableCount());
+  // Adding an empty table gives us one table!
+  ASSERT_EQ(uint32_t(1), table.getTableCount());
 
-    // Adding an empty table doesn't mean we get packages.
-    ASSERT_EQ(uint32_t(0), table.getBasePackageCount());
+  // Adding an empty table doesn't mean we get packages.
+  ASSERT_EQ(uint32_t(0), table.getBasePackageCount());
 
-    Res_value val;
-    ASSERT_LT(table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG), 0);
+  Res_value val;
+  ASSERT_LT(table.getResource(basic::R::integer::number1, &val, MAY_NOT_BE_BAG),
+            0);
 }
 
 void testU16StringToInt(const char16_t* str, uint32_t expectedValue,
                         bool expectSuccess, bool expectHex) {
-    size_t len = std::char_traits<char16_t>::length(str);
+  size_t len = std::char_traits<char16_t>::length(str);
 
-    // Gtest can't print UTF-16 strings, so we have to convert to UTF-8 :(
-    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
-    std::string s = convert.to_bytes(std::u16string(str, len));
+  // Gtest can't print UTF-16 strings, so we have to convert to UTF-8 :(
+  std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
+  std::string s = convert.to_bytes(std::u16string(str, len));
 
-    Res_value out = {};
-    ASSERT_EQ(expectSuccess, U16StringToInt(str, len, &out))
-        << "Failed with " << s;
+  Res_value out = {};
+  ASSERT_EQ(expectSuccess, U16StringToInt(str, len, &out)) << "Failed with "
+                                                           << s;
 
-    if (!expectSuccess) {
-        ASSERT_EQ(out.TYPE_NULL, out.dataType) << "Failed with " << s;
-        return;
-    }
+  if (!expectSuccess) {
+    ASSERT_EQ(out.TYPE_NULL, out.dataType) << "Failed with " << s;
+    return;
+  }
 
-    if (expectHex) {
-        ASSERT_EQ(out.TYPE_INT_HEX, out.dataType) << "Failed with " << s;
-    } else {
-        ASSERT_EQ(out.TYPE_INT_DEC, out.dataType) << "Failed with " << s;
-    }
+  if (expectHex) {
+    ASSERT_EQ(out.TYPE_INT_HEX, out.dataType) << "Failed with " << s;
+  } else {
+    ASSERT_EQ(out.TYPE_INT_DEC, out.dataType) << "Failed with " << s;
+  }
 
-    ASSERT_EQ(expectedValue, out.data) << "Failed with " << s;
+  ASSERT_EQ(expectedValue, out.data) << "Failed with " << s;
 }
 
 TEST(ResTableTest, U16StringToInt) {
-    testU16StringToInt(u"", 0U, false, false);
-    testU16StringToInt(u"    ", 0U, false, false);
-    testU16StringToInt(u"\t\n", 0U, false, false);
+  testU16StringToInt(u"", 0U, false, false);
+  testU16StringToInt(u"    ", 0U, false, false);
+  testU16StringToInt(u"\t\n", 0U, false, false);
 
-    testU16StringToInt(u"abcd", 0U, false, false);
-    testU16StringToInt(u"10abcd", 0U, false, false);
-    testU16StringToInt(u"42 42", 0U, false, false);
-    testU16StringToInt(u"- 42", 0U, false, false);
-    testU16StringToInt(u"-", 0U, false, false);
+  testU16StringToInt(u"abcd", 0U, false, false);
+  testU16StringToInt(u"10abcd", 0U, false, false);
+  testU16StringToInt(u"42 42", 0U, false, false);
+  testU16StringToInt(u"- 42", 0U, false, false);
+  testU16StringToInt(u"-", 0U, false, false);
 
-    testU16StringToInt(u"0x", 0U, false, true);
-    testU16StringToInt(u"0xnope", 0U, false, true);
-    testU16StringToInt(u"0X42", 0U, false, true);
-    testU16StringToInt(u"0x42 0x42", 0U, false, true);
-    testU16StringToInt(u"-0x0", 0U, false, true);
-    testU16StringToInt(u"-0x42", 0U, false, true);
-    testU16StringToInt(u"- 0x42", 0U, false, true);
+  testU16StringToInt(u"0x", 0U, false, true);
+  testU16StringToInt(u"0xnope", 0U, false, true);
+  testU16StringToInt(u"0X42", 0U, false, true);
+  testU16StringToInt(u"0x42 0x42", 0U, false, true);
+  testU16StringToInt(u"-0x0", 0U, false, true);
+  testU16StringToInt(u"-0x42", 0U, false, true);
+  testU16StringToInt(u"- 0x42", 0U, false, true);
 
-    // Note that u" 42" would pass. This preserves the old behavior, but it may
-    // not be desired.
-    testU16StringToInt(u"42 ", 0U, false, false);
-    testU16StringToInt(u"0x42 ", 0U, false, true);
+  // Note that u" 42" would pass. This preserves the old behavior, but it may
+  // not be desired.
+  testU16StringToInt(u"42 ", 0U, false, false);
+  testU16StringToInt(u"0x42 ", 0U, false, true);
 
-    // Decimal cases.
-    testU16StringToInt(u"0", 0U, true, false);
-    testU16StringToInt(u"-0", 0U, true, false);
-    testU16StringToInt(u"42", 42U, true, false);
-    testU16StringToInt(u" 42", 42U, true, false);
-    testU16StringToInt(u"-42", static_cast<uint32_t>(-42), true, false);
-    testU16StringToInt(u" -42", static_cast<uint32_t>(-42), true, false);
-    testU16StringToInt(u"042", 42U, true, false);
-    testU16StringToInt(u"-042", static_cast<uint32_t>(-42), true, false);
+  // Decimal cases.
+  testU16StringToInt(u"0", 0U, true, false);
+  testU16StringToInt(u"-0", 0U, true, false);
+  testU16StringToInt(u"42", 42U, true, false);
+  testU16StringToInt(u" 42", 42U, true, false);
+  testU16StringToInt(u"-42", static_cast<uint32_t>(-42), true, false);
+  testU16StringToInt(u" -42", static_cast<uint32_t>(-42), true, false);
+  testU16StringToInt(u"042", 42U, true, false);
+  testU16StringToInt(u"-042", static_cast<uint32_t>(-42), true, false);
 
-    // Hex cases.
-    testU16StringToInt(u"0x0", 0x0, true, true);
-    testU16StringToInt(u"0x42", 0x42, true, true);
-    testU16StringToInt(u" 0x42", 0x42, true, true);
+  // Hex cases.
+  testU16StringToInt(u"0x0", 0x0, true, true);
+  testU16StringToInt(u"0x42", 0x42, true, true);
+  testU16StringToInt(u" 0x42", 0x42, true, true);
 
-    // Just before overflow cases:
-    testU16StringToInt(u"2147483647", INT_MAX, true, false);
-    testU16StringToInt(u"-2147483648", static_cast<uint32_t>(INT_MIN), true,
-                       false);
-    testU16StringToInt(u"0xffffffff", UINT_MAX, true, true);
+  // Just before overflow cases:
+  testU16StringToInt(u"2147483647", INT_MAX, true, false);
+  testU16StringToInt(u"-2147483648", static_cast<uint32_t>(INT_MIN), true,
+                     false);
+  testU16StringToInt(u"0xffffffff", UINT_MAX, true, true);
 
-    // Overflow cases:
-    testU16StringToInt(u"2147483648", 0U, false, false);
-    testU16StringToInt(u"-2147483649", 0U, false, false);
-    testU16StringToInt(u"0x1ffffffff", 0U, false, true);
+  // Overflow cases:
+  testU16StringToInt(u"2147483648", 0U, false, false);
+  testU16StringToInt(u"-2147483649", 0U, false, false);
+  testU16StringToInt(u"0x1ffffffff", 0U, false, true);
 }
 
 TEST(ResTableTest, ShareButDontModifyResTable) {
-    ResTable sharedTable;
-    ASSERT_EQ(NO_ERROR, sharedTable.add(basic_arsc, basic_arsc_len));
+  std::string contents;
+  ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk",
+                                      "resources.arsc", &contents));
 
-    ResTable_config param;
-    memset(&param, 0, sizeof(param));
-    param.language[0] = 'v';
-    param.language[1] = 's';
-    sharedTable.setParameters(&param);
+  ResTable sharedTable;
+  ASSERT_EQ(NO_ERROR, sharedTable.add(contents.data(), contents.size()));
 
-    // Check that we get the default value for @integer:number1
-    Res_value val;
-    ssize_t block = sharedTable.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
-    ASSERT_GE(block, 0);
-    ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
-    ASSERT_EQ(uint32_t(600), val.data);
+  ResTable_config param;
+  memset(&param, 0, sizeof(param));
+  param.language[0] = 'v';
+  param.language[1] = 's';
+  sharedTable.setParameters(&param);
 
-    // Create a new table that shares the entries of the shared table.
-    ResTable table;
-    ASSERT_EQ(NO_ERROR, table.add(&sharedTable, false));
+  // Check that we get the default value for @integer:number1
+  Res_value val;
+  ssize_t block =
+      sharedTable.getResource(basic::R::integer::number1, &val, MAY_NOT_BE_BAG);
+  ASSERT_GE(block, 0);
+  ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+  ASSERT_EQ(uint32_t(600), val.data);
 
-    // Set a new configuration on the new table.
-    memset(&param, 0, sizeof(param));
-    param.language[0] = 's';
-    param.language[1] = 'v';
-    param.country[0] = 'S';
-    param.country[1] = 'E';
-    table.setParameters(&param);
+  // Create a new table that shares the entries of the shared table.
+  ResTable table;
+  ASSERT_EQ(NO_ERROR, table.add(&sharedTable, false));
 
-    // Check that we get a new value in the new table.
-    block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
-    ASSERT_GE(block, 0);
-    ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
-    ASSERT_EQ(uint32_t(400), val.data);
+  // Set a new configuration on the new table.
+  memset(&param, 0, sizeof(param));
+  param.language[0] = 's';
+  param.language[1] = 'v';
+  param.country[0] = 'S';
+  param.country[1] = 'E';
+  table.setParameters(&param);
 
-    // Check that we still get the old value in the shared table.
-    block = sharedTable.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
-    ASSERT_GE(block, 0);
-    ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
-    ASSERT_EQ(uint32_t(600), val.data);
+  // Check that we get a new value in the new table.
+  block = table.getResource(basic::R::integer::number1, &val, MAY_NOT_BE_BAG);
+  ASSERT_GE(block, 0);
+  ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+  ASSERT_EQ(uint32_t(400), val.data);
+
+  // Check that we still get the old value in the shared table.
+  block =
+      sharedTable.getResource(basic::R::integer::number1, &val, MAY_NOT_BE_BAG);
+  ASSERT_GE(block, 0);
+  ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+  ASSERT_EQ(uint32_t(600), val.data);
 }
 
 TEST(ResTableTest, GetConfigurationsReturnsUniqueList) {
-    ResTable table;
-    ASSERT_EQ(NO_ERROR, table.add(system_arsc, system_arsc_len));
-    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+  std::string contents;
+  ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk",
+                                      "resources.arsc", &contents));
 
-    ResTable_config configSv;
-    memset(&configSv, 0, sizeof(configSv));
-    configSv.language[0] = 's';
-    configSv.language[1] = 'v';
+  std::string system_contents;
+  ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/system/system.apk",
+                                      "resources.arsc", &system_contents));
 
-    Vector<ResTable_config> configs;
-    table.getConfigurations(&configs);
+  ResTable table;
+  ASSERT_EQ(NO_ERROR,
+            table.add(system_contents.data(), system_contents.size()));
+  ASSERT_EQ(NO_ERROR, table.add(contents.data(), contents.size()));
 
-    EXPECT_EQ(1, std::count(configs.begin(), configs.end(), configSv));
+  ResTable_config configSv;
+  memset(&configSv, 0, sizeof(configSv));
+  configSv.language[0] = 's';
+  configSv.language[1] = 'v';
 
-    Vector<String8> locales;
-    table.getLocales(&locales);
+  Vector<ResTable_config> configs;
+  table.getConfigurations(&configs);
 
-    EXPECT_EQ(1, std::count(locales.begin(), locales.end(), String8("sv")));
+  EXPECT_EQ(1, std::count(configs.begin(), configs.end(), configSv));
+
+  Vector<String8> locales;
+  table.getLocales(&locales);
+
+  EXPECT_EQ(1, std::count(locales.begin(), locales.end(), String8("sv")));
 }
 
-} // namespace
+}  // namespace android
diff --git a/libs/androidfw/tests/Split_test.cpp b/libs/androidfw/tests/Split_test.cpp
index b69d685..1f207e2 100644
--- a/libs/androidfw/tests/Split_test.cpp
+++ b/libs/androidfw/tests/Split_test.cpp
@@ -14,233 +14,254 @@
  * limitations under the License.
  */
 
-#include <androidfw/ResourceTypes.h>
+#include "androidfw/ResourceTypes.h"
 
-#include <utils/String8.h>
-#include <utils/String16.h>
+#include "utils/String16.h"
+#include "utils/String8.h"
+
 #include "TestHelpers.h"
 #include "data/basic/R.h"
 
-#include <gtest/gtest.h>
+using com::android::basic::R;
 
-using namespace android;
+namespace android {
 
-namespace {
-
-/**
- * Include a binary resource table. This table
- * is a base table for an APK split.
- *
- * Package: com.android.test.basic
- */
-#include "data/basic/basic_arsc.h"
-
-/**
- * Include a binary resource table. This table
- * is a configuration split table for an APK split.
- *
- * Package: com.android.test.basic
- */
-#include "data/basic/split_de_fr_arsc.h"
-#include "data/basic/split_hdpi_v4_arsc.h"
-#include "data/basic/split_xhdpi_v4_arsc.h"
-#include "data/basic/split_xxhdpi_v4_arsc.h"
-
-/**
- * Include a binary resource table. This table
- * is a feature split table for an APK split.
- *
- * Package: com.android.test.basic
- */
-#include "data/feature/feature_arsc.h"
-
-enum { MAY_NOT_BE_BAG = false };
-
-void makeConfigFrench(ResTable_config* config) {
-    memset(config, 0, sizeof(*config));
-    config->language[0] = 'f';
-    config->language[1] = 'r';
+static void makeConfigFrench(ResTable_config* config) {
+  memset(config, 0, sizeof(*config));
+  config->language[0] = 'f';
+  config->language[1] = 'r';
 }
 
-TEST(SplitTest, TestLoadBase) {
-    ResTable table;
-    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+class SplitTest : public ::testing::Test {
+ public:
+  void SetUp() override {
+    ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk",
+                                        "resources.arsc", &basic_contents_));
+    ASSERT_TRUE(
+        ReadFileFromZipToString(GetTestDataPath() + "/basic/basic_de_fr.apk",
+                                "resources.arsc", &basic_de_fr_contents_));
+    ASSERT_TRUE(
+        ReadFileFromZipToString(GetTestDataPath() + "/basic/basic_hdpi-v4.apk",
+                                "resources.arsc", &basic_hdpi_contents_));
+    ASSERT_TRUE(
+        ReadFileFromZipToString(GetTestDataPath() + "/basic/basic_xhdpi-v4.apk",
+                                "resources.arsc", &basic_xhdpi_contents_));
+    ASSERT_TRUE(ReadFileFromZipToString(
+        GetTestDataPath() + "/basic/basic_xxhdpi-v4.apk", "resources.arsc",
+        &basic_xxhdpi_contents_));
+    ASSERT_TRUE(
+        ReadFileFromZipToString(GetTestDataPath() + "/feature/feature.apk",
+                                "resources.arsc", &feature_contents_));
+  }
+
+ protected:
+  std::string basic_contents_;
+  std::string basic_de_fr_contents_;
+  std::string basic_hdpi_contents_;
+  std::string basic_xhdpi_contents_;
+  std::string basic_xxhdpi_contents_;
+  std::string feature_contents_;
+};
+
+TEST_F(SplitTest, TestLoadBase) {
+  ResTable table;
+  ASSERT_EQ(NO_ERROR,
+            table.add(basic_contents_.data(), basic_contents_.size()));
 }
 
-TEST(SplitTest, TestGetResourceFromBase) {
-    ResTable_config frenchConfig;
-    makeConfigFrench(&frenchConfig);
+TEST_F(SplitTest, TestGetResourceFromBase) {
+  ResTable_config frenchConfig;
+  makeConfigFrench(&frenchConfig);
 
-    ResTable table;
-    table.setParameters(&frenchConfig);
+  ResTable table;
+  table.setParameters(&frenchConfig);
 
-    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+  ASSERT_EQ(NO_ERROR,
+            table.add(basic_contents_.data(), basic_contents_.size()));
 
-    ResTable_config expectedConfig;
-    memset(&expectedConfig, 0, sizeof(expectedConfig));
+  ResTable_config expectedConfig;
+  memset(&expectedConfig, 0, sizeof(expectedConfig));
 
-    Res_value val;
-    ResTable_config config;
-    ssize_t block = table.getResource(base::R::string::test1, &val, MAY_NOT_BE_BAG, 0, NULL, &config);
+  Res_value val;
+  ResTable_config config;
+  ssize_t block = table.getResource(R::string::test1, &val, MAY_NOT_BE_BAG, 0,
+                                    NULL, &config);
 
-    // The returned block should tell us which string pool to get the value, if it is a string.
-    EXPECT_GE(block, 0);
+  // The returned block should tell us which string pool to get the value, if it
+  // is a string.
+  EXPECT_GE(block, 0);
 
-    // We expect the default resource to be selected since it is the only resource configuration.
-    EXPECT_EQ(0, expectedConfig.compare(config));
+  // We expect the default resource to be selected since it is the only resource
+  // configuration.
+  EXPECT_EQ(0, expectedConfig.compare(config));
 
-    EXPECT_EQ(Res_value::TYPE_STRING, val.dataType);
+  EXPECT_EQ(Res_value::TYPE_STRING, val.dataType);
 }
 
-TEST(SplitTest, TestGetResourceFromSplit) {
-    ResTable_config expectedConfig;
-    makeConfigFrench(&expectedConfig);
+TEST_F(SplitTest, TestGetResourceFromSplit) {
+  ResTable_config expectedConfig;
+  makeConfigFrench(&expectedConfig);
 
-    ResTable table;
-    table.setParameters(&expectedConfig);
+  ResTable table;
+  table.setParameters(&expectedConfig);
 
-    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
-    ASSERT_EQ(NO_ERROR, table.add(split_de_fr_arsc, split_de_fr_arsc_len));
+  ASSERT_EQ(NO_ERROR,
+            table.add(basic_contents_.data(), basic_contents_.size()));
+  ASSERT_EQ(NO_ERROR, table.add(basic_de_fr_contents_.data(),
+                                basic_de_fr_contents_.size()));
 
-    Res_value val;
-    ResTable_config config;
-    ssize_t block = table.getResource(base::R::string::test1, &val, MAY_NOT_BE_BAG, 0, NULL, &config);
+  Res_value val;
+  ResTable_config config;
+  ssize_t block = table.getResource(R::string::test1, &val, MAY_NOT_BE_BAG, 0,
+                                    NULL, &config);
 
-    EXPECT_GE(block, 0);
+  EXPECT_GE(block, 0);
 
-    EXPECT_EQ(0, expectedConfig.compare(config));
+  EXPECT_EQ(0, expectedConfig.compare(config));
 
-    EXPECT_EQ(Res_value::TYPE_STRING, val.dataType);
+  EXPECT_EQ(Res_value::TYPE_STRING, val.dataType);
 }
 
-TEST(SplitTest, ResourcesFromBaseAndSplitHaveSameNames) {
-    ResTable_config expectedConfig;
-    makeConfigFrench(&expectedConfig);
+TEST_F(SplitTest, ResourcesFromBaseAndSplitHaveSameNames) {
+  ResTable_config expectedConfig;
+  makeConfigFrench(&expectedConfig);
 
-    ResTable table;
-    table.setParameters(&expectedConfig);
+  ResTable table;
+  table.setParameters(&expectedConfig);
 
-    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+  ASSERT_EQ(NO_ERROR,
+            table.add(basic_contents_.data(), basic_contents_.size()));
 
-    ResTable::resource_name baseName;
-    EXPECT_TRUE(table.getResourceName(base::R::string::test1, false, &baseName));
+  ResTable::resource_name baseName;
+  EXPECT_TRUE(table.getResourceName(R::string::test1, false, &baseName));
 
-    ASSERT_EQ(NO_ERROR, table.add(split_de_fr_arsc, split_de_fr_arsc_len));
+  ASSERT_EQ(NO_ERROR, table.add(basic_de_fr_contents_.data(),
+                                basic_de_fr_contents_.size()));
 
-    ResTable::resource_name frName;
-    EXPECT_TRUE(table.getResourceName(base::R::string::test1, false, &frName));
+  ResTable::resource_name frName;
+  EXPECT_TRUE(table.getResourceName(R::string::test1, false, &frName));
 
-    EXPECT_EQ(
-            String16(baseName.package, baseName.packageLen),
+  EXPECT_EQ(String16(baseName.package, baseName.packageLen),
             String16(frName.package, frName.packageLen));
 
-    EXPECT_EQ(
-            String16(baseName.type, baseName.typeLen),
+  EXPECT_EQ(String16(baseName.type, baseName.typeLen),
             String16(frName.type, frName.typeLen));
 
-    EXPECT_EQ(
-            String16(baseName.name, baseName.nameLen),
+  EXPECT_EQ(String16(baseName.name, baseName.nameLen),
             String16(frName.name, frName.nameLen));
 }
 
-TEST(SplitTest, TypeEntrySpecFlagsAreUpdated) {
-    ResTable_config defaultConfig;
-    memset(&defaultConfig, 0, sizeof(defaultConfig));
+TEST_F(SplitTest, TypeEntrySpecFlagsAreUpdated) {
+  ResTable_config defaultConfig;
+  memset(&defaultConfig, 0, sizeof(defaultConfig));
 
-    ResTable table;
-    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+  ResTable table;
+  ASSERT_EQ(NO_ERROR,
+            table.add(basic_contents_.data(), basic_contents_.size()));
 
-    Res_value val;
-    uint32_t specFlags = 0;
-    ssize_t block = table.getResource(base::R::string::test1, &val, MAY_NOT_BE_BAG, 0, &specFlags, NULL);
-    EXPECT_GE(block, 0);
+  Res_value val;
+  uint32_t specFlags = 0;
+  ssize_t block = table.getResource(R::string::test1, &val, MAY_NOT_BE_BAG, 0,
+                                    &specFlags, NULL);
+  EXPECT_GE(block, 0);
 
-    EXPECT_EQ(static_cast<uint32_t>(0), specFlags);
+  EXPECT_EQ(static_cast<uint32_t>(0), specFlags);
 
-    ASSERT_EQ(NO_ERROR, table.add(split_de_fr_arsc, split_de_fr_arsc_len));
+  ASSERT_EQ(NO_ERROR, table.add(basic_de_fr_contents_.data(),
+                                basic_de_fr_contents_.size()));
 
-    uint32_t frSpecFlags = 0;
-    block = table.getResource(base::R::string::test1, &val, MAY_NOT_BE_BAG, 0, &frSpecFlags, NULL);
-    EXPECT_GE(block, 0);
+  uint32_t frSpecFlags = 0;
+  block = table.getResource(R::string::test1, &val, MAY_NOT_BE_BAG, 0,
+                            &frSpecFlags, NULL);
+  EXPECT_GE(block, 0);
 
-    EXPECT_EQ(ResTable_config::CONFIG_LOCALE, frSpecFlags);
+  EXPECT_EQ(ResTable_config::CONFIG_LOCALE, frSpecFlags);
 }
 
-TEST(SplitTest, SelectBestDensity) {
-    ResTable_config baseConfig;
-    memset(&baseConfig, 0, sizeof(baseConfig));
-    baseConfig.density = ResTable_config::DENSITY_XHIGH;
-    baseConfig.sdkVersion = 21;
+TEST_F(SplitTest, SelectBestDensity) {
+  ResTable_config baseConfig;
+  memset(&baseConfig, 0, sizeof(baseConfig));
+  baseConfig.density = ResTable_config::DENSITY_XHIGH;
+  baseConfig.sdkVersion = 21;
 
-    ResTable table;
-    table.setParameters(&baseConfig);
-    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
-    ASSERT_EQ(NO_ERROR, table.add(split_hdpi_v4_arsc, split_hdpi_v4_arsc_len));
+  ResTable table;
+  table.setParameters(&baseConfig);
+  ASSERT_EQ(NO_ERROR,
+            table.add(basic_contents_.data(), basic_contents_.size()));
+  ASSERT_EQ(NO_ERROR, table.add(basic_hdpi_contents_.data(),
+                                basic_hdpi_contents_.size()));
 
-    EXPECT_TRUE(IsStringEqual(table, base::R::string::density, "hdpi"));
+  EXPECT_TRUE(IsStringEqual(table, R::string::density, "hdpi"));
 
-    ASSERT_EQ(NO_ERROR, table.add(split_xhdpi_v4_arsc, split_xhdpi_v4_arsc_len));
+  ASSERT_EQ(NO_ERROR, table.add(basic_xhdpi_contents_.data(),
+                                basic_xhdpi_contents_.size()));
 
-    EXPECT_TRUE(IsStringEqual(table, base::R::string::density, "xhdpi"));
+  EXPECT_TRUE(IsStringEqual(table, R::string::density, "xhdpi"));
 
-    ASSERT_EQ(NO_ERROR, table.add(split_xxhdpi_v4_arsc, split_xxhdpi_v4_arsc_len));
+  ASSERT_EQ(NO_ERROR, table.add(basic_xxhdpi_contents_.data(),
+                                basic_xxhdpi_contents_.size()));
 
-    EXPECT_TRUE(IsStringEqual(table, base::R::string::density, "xhdpi"));
+  EXPECT_TRUE(IsStringEqual(table, R::string::density, "xhdpi"));
 
-    baseConfig.density = ResTable_config::DENSITY_XXHIGH;
-    table.setParameters(&baseConfig);
+  baseConfig.density = ResTable_config::DENSITY_XXHIGH;
+  table.setParameters(&baseConfig);
 
-    EXPECT_TRUE(IsStringEqual(table, base::R::string::density, "xxhdpi"));
+  EXPECT_TRUE(IsStringEqual(table, R::string::density, "xxhdpi"));
 }
 
-TEST(SplitFeatureTest, TestNewResourceIsAccessible) {
-    ResTable table;
-    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+TEST_F(SplitTest, TestNewResourceIsAccessible) {
+  ResTable table;
+  ASSERT_EQ(NO_ERROR,
+            table.add(basic_contents_.data(), basic_contents_.size()));
 
-    Res_value val;
-    ssize_t block = table.getResource(base::R::string::test3, &val, MAY_NOT_BE_BAG);
-    EXPECT_LT(block, 0);
+  Res_value val;
+  ssize_t block = table.getResource(R::string::test3, &val, MAY_NOT_BE_BAG);
+  EXPECT_LT(block, 0);
 
-    ASSERT_EQ(NO_ERROR, table.add(feature_arsc, feature_arsc_len));
+  ASSERT_EQ(NO_ERROR,
+            table.add(feature_contents_.data(), feature_contents_.size()));
 
-    block = table.getResource(base::R::string::test3, &val, MAY_NOT_BE_BAG);
-    EXPECT_GE(block, 0);
+  block = table.getResource(R::string::test3, &val, MAY_NOT_BE_BAG);
+  EXPECT_GE(block, 0);
 
-    EXPECT_EQ(Res_value::TYPE_STRING, val.dataType);
+  EXPECT_EQ(Res_value::TYPE_STRING, val.dataType);
 }
 
-TEST(SplitFeatureTest, TestNewResourceNameHasCorrectName) {
-    ResTable table;
-    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+TEST_F(SplitTest, TestNewResourceNameHasCorrectName) {
+  ResTable table;
+  ASSERT_EQ(NO_ERROR,
+            table.add(basic_contents_.data(), basic_contents_.size()));
 
-    ResTable::resource_name name;
-    EXPECT_FALSE(table.getResourceName(base::R::string::test3, false, &name));
+  ResTable::resource_name name;
+  EXPECT_FALSE(table.getResourceName(R::string::test3, false, &name));
 
-    ASSERT_EQ(NO_ERROR, table.add(feature_arsc, feature_arsc_len));
+  ASSERT_EQ(NO_ERROR,
+            table.add(feature_contents_.data(), feature_contents_.size()));
 
-    ASSERT_TRUE(table.getResourceName(base::R::string::test3, false, &name));
+  ASSERT_TRUE(table.getResourceName(R::string::test3, false, &name));
 
-    EXPECT_EQ(String16("com.android.test.basic"),
+  EXPECT_EQ(String16("com.android.basic"),
             String16(name.package, name.packageLen));
 
-    EXPECT_EQ(String16("string"),
-            String16(name.type, name.typeLen));
+  EXPECT_EQ(String16("string"), String16(name.type, name.typeLen));
 
-    EXPECT_EQ(String16("test3"),
-            String16(name.name, name.nameLen));
+  EXPECT_EQ(String16("test3"), String16(name.name, name.nameLen));
 }
 
-TEST(SplitFeatureTest, TestNewResourceIsAccessibleByName) {
-    ResTable table;
-    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
-    ASSERT_EQ(NO_ERROR, table.add(feature_arsc, feature_arsc_len));
+TEST_F(SplitTest, TestNewResourceIsAccessibleByName) {
+  ResTable table;
+  ASSERT_EQ(NO_ERROR,
+            table.add(basic_contents_.data(), basic_contents_.size()));
+  ASSERT_EQ(NO_ERROR,
+            table.add(feature_contents_.data(), feature_contents_.size()));
 
-    const String16 name("test3");
-    const String16 type("string");
-    const String16 package("com.android.test.basic");
-    ASSERT_EQ(base::R::string::test3, table.identifierForName(name.string(), name.size(),
-                                                              type.string(), type.size(),
-                                                              package.string(), package.size()));
+  const String16 name("test3");
+  const String16 type("string");
+  const String16 package("com.android.basic");
+  ASSERT_EQ(
+      R::string::test3,
+      table.identifierForName(name.string(), name.size(), type.string(),
+                              type.size(), package.string(), package.size()));
 }
 
-} // namespace
+}  // namespace
diff --git a/libs/androidfw/tests/TestHelpers.cpp b/libs/androidfw/tests/TestHelpers.cpp
index 3d1d5f5..2c834b1 100644
--- a/libs/androidfw/tests/TestHelpers.cpp
+++ b/libs/androidfw/tests/TestHelpers.cpp
@@ -16,25 +16,56 @@
 
 #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"
+#include "ziparchive/zip_archive.h"
 
 namespace android {
 
+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 ReadFileFromZipToString(const std::string& zip_path,
+                                                   const std::string& file,
+                                                   std::string* out_contents) {
+  out_contents->clear();
+  ::ZipArchiveHandle handle;
+  int32_t result = OpenArchive(zip_path.c_str(), &handle);
+  if (result != 0) {
+    return ::testing::AssertionFailure() << "Failed to open zip '" << zip_path
+                                         << "': " << ::ErrorCodeString(result);
+  }
+
+  ::ZipString name(file.c_str());
+  ::ZipEntry entry;
+  result = ::FindEntry(handle, name, &entry);
+  if (result != 0) {
+    ::CloseArchive(handle);
+    return ::testing::AssertionFailure() << "Could not find file '" << file << "' in zip '"
+                                         << zip_path << "' : " << ::ErrorCodeString(result);
+  }
+
+  out_contents->resize(entry.uncompressed_length);
+  result = ::ExtractToMemory(
+      handle, &entry, const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(out_contents->data())),
+      out_contents->size());
+  if (result != 0) {
+    ::CloseArchive(handle);
+    return ::testing::AssertionFailure() << "Failed to extract file '" << file << "' from zip '"
+                                         << zip_path << "': " << ::ErrorCodeString(result);
+  }
+
+  ::CloseArchive(handle);
+  return ::testing::AssertionSuccess();
+}
+
 ::testing::AssertionResult IsStringEqual(const ResTable& table, uint32_t resource_id,
                                          const char* expected_str) {
   Res_value val;
diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h
index 5f0c4552..d9cee22 100644
--- a/libs/androidfw/tests/TestHelpers.h
+++ b/libs/androidfw/tests/TestHelpers.h
@@ -14,18 +14,16 @@
  * 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) {
   return out << str.string();
@@ -39,12 +37,19 @@
 
 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();
+
+::testing::AssertionResult ReadFileFromZipToString(const std::string& zip_path,
+                                                   const std::string& file,
+                                                   std::string* out_contents);
+
+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();
 }
 
@@ -53,4 +58,4 @@
 
 }  // namespace android
 
-#endif  // __TEST_HELPERS_H
+#endif  // TEST_HELPERS_H_
diff --git a/libs/androidfw/tests/Theme_test.cpp b/libs/androidfw/tests/Theme_test.cpp
index 4d07130..3774657 100644
--- a/libs/androidfw/tests/Theme_test.cpp
+++ b/libs/androidfw/tests/Theme_test.cpp
@@ -14,55 +14,59 @@
  * limitations under the License.
  */
 
-#include <androidfw/ResourceTypes.h>
+#include "androidfw/ResourceTypes.h"
 
-#include <utils/String8.h>
-#include <utils/String16.h>
+#include "utils/String16.h"
+#include "utils/String8.h"
+
 #include "TestHelpers.h"
-#include "data/system/R.h"
 #include "data/app/R.h"
+#include "data/system/R.h"
 
-#include <gtest/gtest.h>
+namespace app = com::android::app;
 
-using namespace android;
-
-namespace {
-
-#include "data/system/system_arsc.h"
-#include "data/app/app_arsc.h"
-
-enum { MAY_NOT_BE_BAG = false };
+namespace android {
 
 /**
  * TODO(adamlesinski): Enable when fixed.
  */
 TEST(ThemeTest, DISABLED_shouldCopyThemeFromDifferentResTable) {
-    ResTable table;
-    ASSERT_EQ(NO_ERROR, table.add(system_arsc, system_arsc_len));
-    ASSERT_EQ(NO_ERROR, table.add(app_arsc, app_arsc_len));
+  ResTable table;
 
-    ResTable::Theme theme1(table);
-    ASSERT_EQ(NO_ERROR, theme1.applyStyle(app::R::style::Theme_One));
-    Res_value val;
-    ASSERT_GE(theme1.getAttribute(android::R::attr::background, &val), 0);
-    ASSERT_EQ(Res_value::TYPE_INT_COLOR_RGB8, val.dataType);
-    ASSERT_EQ(uint32_t(0xffff0000), val.data);
-    ASSERT_GE(theme1.getAttribute(app::R::attr::number, &val), 0);
-    ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
-    ASSERT_EQ(uint32_t(1), val.data);
+  std::string system_contents;
+  ASSERT_TRUE(ReadFileFromZipToString("/system/system.apk", "resources.arsc",
+                                      &system_contents));
+  ASSERT_EQ(NO_ERROR,
+            table.add(system_contents.data(), system_contents.size()));
 
-    ResTable table2;
-    ASSERT_EQ(NO_ERROR, table2.add(system_arsc, system_arsc_len));
-    ASSERT_EQ(NO_ERROR, table2.add(app_arsc, app_arsc_len));
+  std::string app_contents;
+  ASSERT_TRUE(ReadFileFromZipToString("/basic/basic.apk", "resources.arsc",
+                                      &app_contents));
+  ASSERT_EQ(NO_ERROR, table.add(app_contents.data(), app_contents.size()));
 
-    ResTable::Theme theme2(table2);
-    ASSERT_EQ(NO_ERROR, theme2.setTo(theme1));
-    ASSERT_GE(theme2.getAttribute(android::R::attr::background, &val), 0);
-    ASSERT_EQ(Res_value::TYPE_INT_COLOR_RGB8, val.dataType);
-    ASSERT_EQ(uint32_t(0xffff0000), val.data);
-    ASSERT_GE(theme2.getAttribute(app::R::attr::number, &val), 0);
-    ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
-    ASSERT_EQ(uint32_t(1), val.data);
+  ResTable::Theme theme1(table);
+  ASSERT_EQ(NO_ERROR, theme1.applyStyle(app::R::style::Theme_One));
+  Res_value val;
+  ASSERT_GE(theme1.getAttribute(android::R::attr::background, &val), 0);
+  ASSERT_EQ(Res_value::TYPE_INT_COLOR_RGB8, val.dataType);
+  ASSERT_EQ(uint32_t(0xffff0000), val.data);
+  ASSERT_GE(theme1.getAttribute(app::R::attr::number, &val), 0);
+  ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+  ASSERT_EQ(uint32_t(1), val.data);
+
+  ResTable table2;
+  ASSERT_EQ(NO_ERROR,
+            table2.add(system_contents.data(), system_contents.size()));
+  ASSERT_EQ(NO_ERROR, table2.add(app_contents.data(), app_contents.size()));
+
+  ResTable::Theme theme2(table2);
+  ASSERT_EQ(NO_ERROR, theme2.setTo(theme1));
+  ASSERT_GE(theme2.getAttribute(android::R::attr::background, &val), 0);
+  ASSERT_EQ(Res_value::TYPE_INT_COLOR_RGB8, val.dataType);
+  ASSERT_EQ(uint32_t(0xffff0000), val.data);
+  ASSERT_GE(theme2.getAttribute(app::R::attr::number, &val), 0);
+  ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+  ASSERT_EQ(uint32_t(1), val.data);
 }
 
-}
+}  // namespace android
diff --git a/libs/androidfw/tests/data/app/R.h b/libs/androidfw/tests/data/app/R.h
index 23e68e3..5be2eee 100644
--- a/libs/androidfw/tests/data/app/R.h
+++ b/libs/androidfw/tests/data/app/R.h
@@ -14,25 +14,31 @@
  * limitations under the License.
  */
 
-#ifndef __APP_R_H
-#define __APP_R_H
+#ifndef TEST_DATA_APP_R_H_
+#define TEST_DATA_APP_R_H_
 
+#include <cstdint>
+
+namespace com {
+namespace android {
 namespace app {
-namespace R {
 
-namespace attr {
-    enum {
-        number         = 0x7f010000,   // default
+struct R {
+  struct attr {
+    enum : uint32_t {
+      number = 0x7f010000,  // default
     };
-}
+  };
 
-namespace style {
-    enum {
-        Theme_One      = 0x7f020000,   // default
+  struct style {
+    enum : uint32_t {
+      Theme_One = 0x7f020000,  // default
     };
-}
+  };
+};
 
-} // namespace R
-} // namespace app
+}  // namespace app
+}  // namespace android
+}  // namespace com
 
-#endif // __APP_R_H
+#endif  // TEST_DATA_APP_R_H_
diff --git a/libs/androidfw/tests/data/app/app.apk b/libs/androidfw/tests/data/app/app.apk
new file mode 100644
index 0000000..ccb0824
--- /dev/null
+++ b/libs/androidfw/tests/data/app/app.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/app/app_arsc.h b/libs/androidfw/tests/data/app/app_arsc.h
deleted file mode 100644
index d5d9a3b..0000000
--- a/libs/androidfw/tests/data/app/app_arsc.h
+++ /dev/null
@@ -1,62 +0,0 @@
-unsigned char app_arsc[] = {
-  0x02, 0x00, 0x0c, 0x00, 0xc4, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x9c, 0x02, 0x00, 0x00,
-  0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00,
-  0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00,
-  0x64, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x70, 0x00, 0x70, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00,
-  0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00,
-  0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
-  0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x6e, 0x00,
-  0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00,
-  0x09, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00,
-  0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
-  0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00,
-  0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
-  0x64, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x01, 0x7f, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00
-};
-unsigned int app_arsc_len = 708;
diff --git a/libs/androidfw/tests/data/app/build b/libs/androidfw/tests/data/app/build
index 62257bc..d418158 100755
--- a/libs/androidfw/tests/data/app/build
+++ b/libs/androidfw/tests/data/app/build
@@ -15,7 +15,6 @@
 # limitations under the License.
 #
 
-aapt package -v -I ../system/bundle.apk -M AndroidManifest.xml -S res -F bundle.apk -f && \
-unzip bundle.apk resources.arsc && \
-mv resources.arsc app.arsc && \
-xxd -i app.arsc > app_arsc.h
+set -e
+
+aapt package -I ../system/system.apk -M AndroidManifest.xml -S res -F app.apk -f
diff --git a/libs/androidfw/tests/data/appaslib/R.h b/libs/androidfw/tests/data/appaslib/R.h
index 3af921a..5a21327 100644
--- a/libs/androidfw/tests/data/appaslib/R.h
+++ b/libs/androidfw/tests/data/appaslib/R.h
@@ -14,39 +14,53 @@
  * limitations under the License.
  */
 
-#ifndef __APPASLIB_R_H
-#define __APPASLIB_R_H
+#ifndef DATA_APPASLIB_R_H_
+#define DATA_APPASLIB_R_H_
 
+#include <cstdint>
+
+namespace com {
+namespace android {
 namespace appaslib {
-namespace R {
-namespace lib {
-namespace integer {
-    enum {
-        number1     = 0x02020000,   // default
-    };
-}
 
-namespace array {
-    enum {
-        integerArray1 = 0x02030000,   // default
+namespace lib {
+
+struct R {
+  struct integer {
+    enum : uint32_t {
+      number1 = 0x02020000,  // default
     };
-}
-} // namespace lib
+  };
+
+  struct array {
+    enum : uint32_t {
+      integerArray1 = 0x02030000,  // default
+    };
+  };
+};
+
+}  // namespace lib
 
 namespace app {
-namespace integer {
-    enum {
-        number1     = 0x7f020000,     // default
-    };
-}
 
-namespace array {
-    enum {
-        integerArray1 = 0x7f030000,   // default
+struct R {
+  struct integer {
+    enum : uint32_t {
+      number1 = 0x7f020000,  // default
     };
-}
-} // namespace app
-} // namespace R
-} // namespace appaslib
+  };
 
-#endif // __APPASLIB_R_H
+  struct array {
+    enum : uint32_t {
+      integerArray1 = 0x7f030000,  // default
+    };
+  };
+};
+
+}  // namespace app
+
+}  // namespace appaslib
+}  // namespace android
+}  // namespace com
+
+#endif  // DATA_APPASLIB_R_H_
diff --git a/libs/androidfw/tests/data/appaslib/appaslib.apk b/libs/androidfw/tests/data/appaslib/appaslib.apk
new file mode 100644
index 0000000..6ebd823
--- /dev/null
+++ b/libs/androidfw/tests/data/appaslib/appaslib.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/appaslib/appaslib_arsc.h b/libs/androidfw/tests/data/appaslib/appaslib_arsc.h
deleted file mode 100644
index be176ab..0000000
--- a/libs/androidfw/tests/data/appaslib/appaslib_arsc.h
+++ /dev/null
@@ -1,68 +0,0 @@
-unsigned char appaslib_arsc[] = {
-  0x02, 0x00, 0x0c, 0x00, 0x04, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xdc, 0x02, 0x00, 0x00,
-  0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00,
-  0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00,
-  0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
-  0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00, 0x69, 0x00, 0x63, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x54, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00,
-  0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00, 0x07, 0x00, 0x69, 0x00,
-  0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x72, 0x00,
-  0x00, 0x00, 0x05, 0x00, 0x61, 0x00, 0x72, 0x00, 0x72, 0x00, 0x61, 0x00,
-  0x79, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x54, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x12, 0x00, 0x00, 0x00, 0x07, 0x00, 0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00,
-  0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x31, 0x00, 0x00, 0x00, 0x0d, 0x00,
-  0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00,
-  0x72, 0x00, 0x41, 0x00, 0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00,
-  0x31, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
-  0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x48, 0x00, 0x5c, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
-  0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x7f,
-  0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x48, 0x00,
-  0x80, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x4c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x10, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10,
-  0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10,
-  0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10,
-  0x03, 0x00, 0x00, 0x00
-};
-unsigned int appaslib_arsc_len = 772;
diff --git a/libs/androidfw/tests/data/appaslib/appaslib_lib.apk b/libs/androidfw/tests/data/appaslib/appaslib_lib.apk
new file mode 100644
index 0000000..ee1521c
--- /dev/null
+++ b/libs/androidfw/tests/data/appaslib/appaslib_lib.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/appaslib/appaslib_lib_arsc.h b/libs/androidfw/tests/data/appaslib/appaslib_lib_arsc.h
deleted file mode 100644
index 099285a..0000000
--- a/libs/androidfw/tests/data/appaslib/appaslib_lib_arsc.h
+++ /dev/null
@@ -1,68 +0,0 @@
-unsigned char appaslib_lib_arsc[] = {
-  0x02, 0x00, 0x0c, 0x00, 0x04, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xdc, 0x02, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00,
-  0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00,
-  0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
-  0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00, 0x69, 0x00, 0x63, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x54, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00,
-  0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00, 0x07, 0x00, 0x69, 0x00,
-  0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x72, 0x00,
-  0x00, 0x00, 0x05, 0x00, 0x61, 0x00, 0x72, 0x00, 0x72, 0x00, 0x61, 0x00,
-  0x79, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x54, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x12, 0x00, 0x00, 0x00, 0x07, 0x00, 0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00,
-  0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x31, 0x00, 0x00, 0x00, 0x0d, 0x00,
-  0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00,
-  0x72, 0x00, 0x41, 0x00, 0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00,
-  0x31, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
-  0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x48, 0x00, 0x5c, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
-  0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x00, 0x03, 0x00,
-  0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x48, 0x00,
-  0x80, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x4c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x10, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10,
-  0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10,
-  0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10,
-  0x03, 0x00, 0x00, 0x00
-};
-unsigned int appaslib_lib_arsc_len = 772;
diff --git a/libs/androidfw/tests/data/appaslib/build b/libs/androidfw/tests/data/appaslib/build
index e4bd88b..baaf700 100755
--- a/libs/androidfw/tests/data/appaslib/build
+++ b/libs/androidfw/tests/data/appaslib/build
@@ -15,14 +15,9 @@
 # limitations under the License.
 #
 
+set -e
+
 PATH_TO_FRAMEWORK_RES=$(gettop)/prebuilts/sdk/current/android.jar
 
-aapt package -M AndroidManifest.xml -S res -I $PATH_TO_FRAMEWORK_RES -F bundle.apk -f && \
-unzip bundle.apk resources.arsc && \
-mv resources.arsc appaslib.arsc && \
-xxd -i appaslib.arsc > appaslib_arsc.h && \
-aapt package -M AndroidManifest.xml -S res -I $PATH_TO_FRAMEWORK_RES -F bundle.apk -f --shared-lib && \
-unzip bundle.apk resources.arsc && \
-mv resources.arsc appaslib_lib.arsc && \
-xxd -i appaslib_lib.arsc > appaslib_lib_arsc.h \
-
+aapt package -M AndroidManifest.xml -S res -I $PATH_TO_FRAMEWORK_RES -F appaslib.apk -f
+aapt package -M AndroidManifest.xml -S res -I $PATH_TO_FRAMEWORK_RES -F appaslib_lib.apk -f --shared-lib
diff --git a/libs/androidfw/tests/data/basic/AndroidManifest.xml b/libs/androidfw/tests/data/basic/AndroidManifest.xml
index a56ac18..b117882 100644
--- a/libs/androidfw/tests/data/basic/AndroidManifest.xml
+++ b/libs/androidfw/tests/data/basic/AndroidManifest.xml
@@ -15,7 +15,6 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.test.basic">
-    <application>
-    </application>
+    package="com.android.basic">
+    <application />
 </manifest>
diff --git a/libs/androidfw/tests/data/basic/R.h b/libs/androidfw/tests/data/basic/R.h
index 6694dd0..9352b5c 100644
--- a/libs/androidfw/tests/data/basic/R.h
+++ b/libs/androidfw/tests/data/basic/R.h
@@ -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.
@@ -14,59 +14,67 @@
  * limitations under the License.
  */
 
-#ifndef __BASE_R_H
-#define __BASE_R_H
+#ifndef TESTS_DATA_BASIC_R_H_
+#define TESTS_DATA_BASIC_R_H_
 
-namespace base {
-namespace R {
+#include <cstdint>
 
-namespace attr {
-    enum {
-        attr1       = 0x7f010000, // default
-        attr2       = 0x7f010001, // default
+namespace com {
+namespace android {
+namespace basic {
+
+struct R {
+  struct attr {
+    enum : uint32_t {
+      attr1 = 0x7f010000,
+      attr2 = 0x7f010001,
     };
-}
+  };
 
-namespace layout {
-    enum {
-        main        = 0x7f020000,  // default, fr-sw600dp-v13
+  struct layout {
+    enum : uint32_t {
+      main = 0x7f020000,
     };
-}
+  };
 
-namespace string {
-    enum {
-        test1       = 0x7f030000,   // default
-        test2       = 0x7f030001,   // default
-        density     = 0x7f030002,   // default
+  struct string {
+    enum : uint32_t {
+      test1 = 0x7f030000,
+      test2 = 0x7f030001,
+      density = 0x7f030002,
 
-        test3       = 0x7f080000,   // default (in feature)
-        test4       = 0x7f080001,   // default (in feature)
+      // From feature
+      test3 = 0x7f080000,
+      test4 = 0x7f080001,
     };
-}
+  };
 
-namespace integer {
-    enum {
-        number1     = 0x7f040000,   // default, sv, vs
-        number2     = 0x7f040001,   // default
+  struct integer {
+    enum : uint32_t {
+      number1 = 0x7f040000,
+      number2 = 0x7f040001,
 
-        test3       = 0x7f090000,   // default (in feature)
+      // From feature
+      number3 = 0x7f090000,
     };
-}
+  };
 
-namespace style {
-    enum {
-        Theme1      = 0x7f050000,   // default
-        Theme2      = 0x7f050001,   // default
+  struct style {
+    enum : uint32_t {
+      Theme1 = 0x7f050000,
+      Theme2 = 0x7f050001,
     };
-}
+  };
 
-namespace array {
-    enum {
-        integerArray1 = 0x7f060000,   // default
+  struct array {
+    enum : uint32_t {
+      integerArray1 = 0x7f060000,
     };
-}
+  };
+};
 
-} // namespace R
-} // namespace base
+}  // namespace basic
+}  // namespace android
+}  // namespace com
 
-#endif // __BASE_R_H
+#endif /* TESTS_DATA_BASIC_R_H_ */
diff --git a/libs/androidfw/tests/data/basic/basic.apk b/libs/androidfw/tests/data/basic/basic.apk
new file mode 100644
index 0000000..2d71f5b
--- /dev/null
+++ b/libs/androidfw/tests/data/basic/basic.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/basic_arsc.h b/libs/androidfw/tests/data/basic/basic_arsc.h
deleted file mode 100644
index e497401..0000000
--- a/libs/androidfw/tests/data/basic/basic_arsc.h
+++ /dev/null
@@ -1,175 +0,0 @@
-unsigned char basic_arsc[] = {
-  0x02, 0x00, 0x0c, 0x00, 0x0c, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x1c, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00,
-  0x72, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x13, 0x00, 0x72, 0x00,
-  0x65, 0x00, 0x73, 0x00, 0x2f, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00,
-  0x6f, 0x00, 0x75, 0x00, 0x74, 0x00, 0x2f, 0x00, 0x6d, 0x00, 0x61, 0x00,
-  0x69, 0x00, 0x6e, 0x00, 0x2e, 0x00, 0x78, 0x00, 0x6d, 0x00, 0x6c, 0x00,
-  0x00, 0x00, 0x22, 0x00, 0x72, 0x00, 0x65, 0x00, 0x73, 0x00, 0x2f, 0x00,
-  0x6c, 0x00, 0x61, 0x00, 0x79, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x74, 0x00,
-  0x2d, 0x00, 0x66, 0x00, 0x72, 0x00, 0x2d, 0x00, 0x73, 0x00, 0x77, 0x00,
-  0x36, 0x00, 0x30, 0x00, 0x30, 0x00, 0x64, 0x00, 0x70, 0x00, 0x2d, 0x00,
-  0x76, 0x00, 0x31, 0x00, 0x33, 0x00, 0x2f, 0x00, 0x6d, 0x00, 0x61, 0x00,
-  0x69, 0x00, 0x6e, 0x00, 0x2e, 0x00, 0x78, 0x00, 0x6d, 0x00, 0x6c, 0x00,
-  0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
-  0x31, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00,
-  0x74, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01,
-  0x44, 0x07, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00,
-  0x6d, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00,
-  0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00,
-  0x73, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00,
-  0x69, 0x00, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x20, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
-  0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
-  0x90, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
-  0x2c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00,
-  0x06, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00, 0x6f, 0x00, 0x75, 0x00,
-  0x74, 0x00, 0x00, 0x00, 0x06, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00,
-  0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00, 0x07, 0x00, 0x69, 0x00,
-  0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x72, 0x00,
-  0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00, 0x6c, 0x00,
-  0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x61, 0x00, 0x72, 0x00, 0x72, 0x00,
-  0x61, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
-  0xec, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
-  0x28, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
-  0x56, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,
-  0x88, 0x00, 0x00, 0x00, 0x05, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00,
-  0x72, 0x00, 0x31, 0x00, 0x00, 0x00, 0x05, 0x00, 0x61, 0x00, 0x74, 0x00,
-  0x74, 0x00, 0x72, 0x00, 0x32, 0x00, 0x00, 0x00, 0x04, 0x00, 0x6d, 0x00,
-  0x61, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00,
-  0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x31, 0x00, 0x00, 0x00, 0x05, 0x00,
-  0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x32, 0x00, 0x00, 0x00,
-  0x07, 0x00, 0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00,
-  0x72, 0x00, 0x31, 0x00, 0x00, 0x00, 0x07, 0x00, 0x6e, 0x00, 0x75, 0x00,
-  0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x32, 0x00, 0x00, 0x00,
-  0x06, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00,
-  0x31, 0x00, 0x00, 0x00, 0x06, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00,
-  0x6d, 0x00, 0x65, 0x00, 0x32, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x69, 0x00,
-  0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x72, 0x00,
-  0x41, 0x00, 0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x31, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00, 0x8c, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
-  0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x08, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x00,
-  0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x04, 0x24, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00,
-  0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x50, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00,
-  0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x50, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x66, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x02,
-  0x00, 0x00, 0x00, 0x00, 0x4c, 0x61, 0x74, 0x6e, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
-  0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x01, 0x02, 0x4c, 0x00, 0x78, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
-  0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00,
-  0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x01, 0x02, 0x4c, 0x00, 0x74, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10,
-  0xc8, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06, 0x7f, 0x01, 0x02, 0x4c, 0x00,
-  0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x54, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x76, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00,
-  0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0x58, 0x02, 0x00, 0x00,
-  0x01, 0x02, 0x4c, 0x00, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x73, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x61, 0x74, 0x6e,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
-  0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10,
-  0x90, 0x01, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
-  0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00, 0x98, 0x00, 0x00, 0x00,
-  0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
-  0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x28, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7f,
-  0x08, 0x00, 0x00, 0x10, 0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x7f,
-  0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x7f, 0x10, 0x00, 0x01, 0x00,
-  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x7f, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x01, 0x7f, 0x08, 0x00, 0x00, 0x10, 0x2c, 0x01, 0x00, 0x00,
-  0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00,
-  0x84, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x50, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
-  0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02,
-  0x08, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02,
-  0x08, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x00
-};
-unsigned int basic_arsc_len = 2060;
diff --git a/libs/androidfw/tests/data/basic/basic_de_fr.apk b/libs/androidfw/tests/data/basic/basic_de_fr.apk
new file mode 100644
index 0000000..69a2f30
--- /dev/null
+++ b/libs/androidfw/tests/data/basic/basic_de_fr.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/basic_hdpi-v4.apk b/libs/androidfw/tests/data/basic/basic_hdpi-v4.apk
new file mode 100644
index 0000000..011808b
--- /dev/null
+++ b/libs/androidfw/tests/data/basic/basic_hdpi-v4.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/basic_xhdpi-v4.apk b/libs/androidfw/tests/data/basic/basic_xhdpi-v4.apk
new file mode 100644
index 0000000..6d4353c
--- /dev/null
+++ b/libs/androidfw/tests/data/basic/basic_xhdpi-v4.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/basic_xxhdpi-v4.apk b/libs/androidfw/tests/data/basic/basic_xxhdpi-v4.apk
new file mode 100644
index 0000000..e3bda88
--- /dev/null
+++ b/libs/androidfw/tests/data/basic/basic_xxhdpi-v4.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/build b/libs/androidfw/tests/data/basic/build
index fd289fa..68b911a 100755
--- a/libs/androidfw/tests/data/basic/build
+++ b/libs/androidfw/tests/data/basic/build
@@ -15,25 +15,8 @@
 # limitations under the License.
 #
 
+set -e
+
 PATH_TO_FRAMEWORK_RES=$(gettop)/prebuilts/sdk/current/android.jar
 
-aapt package -M AndroidManifest.xml -S res -I $PATH_TO_FRAMEWORK_RES --split hdpi --split xhdpi --split xxhdpi --split fr,de -F bundle.apk -f && \
-unzip bundle.apk resources.arsc && \
-mv resources.arsc basic.arsc && \
-xxd -i basic.arsc > basic_arsc.h && \
-\
-unzip bundle_de_fr.apk resources.arsc && \
-mv resources.arsc split_de_fr.arsc && \
-xxd -i split_de_fr.arsc > split_de_fr_arsc.h && \
-\
-unzip bundle_hdpi-v4.apk resources.arsc && \
-mv resources.arsc split_hdpi_v4.arsc && \
-xxd -i split_hdpi_v4.arsc > split_hdpi_v4_arsc.h && \
-\
-unzip bundle_xhdpi-v4.apk resources.arsc && \
-mv resources.arsc split_xhdpi_v4.arsc && \
-xxd -i split_xhdpi_v4.arsc > split_xhdpi_v4_arsc.h && \
-\
-unzip bundle_xxhdpi-v4.apk resources.arsc && \
-mv resources.arsc split_xxhdpi_v4.arsc && \
-xxd -i split_xxhdpi_v4.arsc > split_xxhdpi_v4_arsc.h \
+aapt package -M AndroidManifest.xml -S res -I $PATH_TO_FRAMEWORK_RES --split hdpi --split xhdpi --split xxhdpi --split fr,de -F basic.apk -f
diff --git a/libs/androidfw/tests/data/basic/res/values/values.xml b/libs/androidfw/tests/data/basic/res/values/values.xml
index a010cca..75e0435 100644
--- a/libs/androidfw/tests/data/basic/res/values/values.xml
+++ b/libs/androidfw/tests/data/basic/res/values/values.xml
@@ -25,12 +25,12 @@
     <integer name="number2">@array/integerArray1</integer>
 
     <style name="Theme1">
-        <item name="com.android.test.basic:attr1">100</item>
-        <item name="com.android.test.basic:attr2">@integer/number1</item>
+        <item name="com.android.basic:attr1">100</item>
+        <item name="com.android.basic:attr2">@integer/number1</item>
     </style>
 
-    <style name="Theme2" parent="@com.android.test.basic:style/Theme1">
-        <item name="com.android.test.basic:attr1">300</item>
+    <style name="Theme2" parent="@com.android.basic:style/Theme1">
+        <item name="com.android.basic:attr1">300</item>
     </style>
 
     <integer-array name="integerArray1">
diff --git a/libs/androidfw/tests/data/basic/split_de_fr_arsc.h b/libs/androidfw/tests/data/basic/split_de_fr_arsc.h
deleted file mode 100644
index a2aa598..0000000
--- a/libs/androidfw/tests/data/basic/split_de_fr_arsc.h
+++ /dev/null
@@ -1,88 +0,0 @@
-unsigned char split_de_fr_arsc[] = {
-  0x02, 0x00, 0x0c, 0x00, 0xf4, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x1c, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
-  0x2c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x09, 0x00, 0x76, 0x00,
-  0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x75, 0x00, 0x63, 0x00, 0x68, 0x00,
-  0x20, 0x00, 0x31, 0x00, 0x00, 0x00, 0x09, 0x00, 0x76, 0x00, 0x65, 0x00,
-  0x72, 0x00, 0x73, 0x00, 0x75, 0x00, 0x63, 0x00, 0x68, 0x00, 0x20, 0x00,
-  0x32, 0x00, 0x00, 0x00, 0x07, 0x00, 0x65, 0x00, 0x73, 0x00, 0x73, 0x00,
-  0x61, 0x00, 0x69, 0x00, 0x20, 0x00, 0x31, 0x00, 0x00, 0x00, 0x07, 0x00,
-  0x65, 0x00, 0x73, 0x00, 0x73, 0x00, 0x61, 0x00, 0x69, 0x00, 0x20, 0x00,
-  0x32, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x6c, 0x03, 0x00, 0x00,
-  0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00,
-  0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00,
-  0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
-  0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00, 0x69, 0x00, 0x63, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
-  0x06, 0x00, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x90, 0x00, 0x00, 0x00,
-  0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
-  0x3e, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00,
-  0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00, 0x06, 0x00, 0x6c, 0x00,
-  0x61, 0x00, 0x79, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x74, 0x00, 0x00, 0x00,
-  0x06, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00,
-  0x67, 0x00, 0x00, 0x00, 0x07, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00,
-  0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00,
-  0x73, 0x00, 0x74, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00,
-  0x05, 0x00, 0x61, 0x00, 0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0e, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00,
-  0x74, 0x00, 0x31, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00,
-  0x73, 0x00, 0x74, 0x00, 0x32, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
-  0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
-  0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x1c, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00,
-  0x78, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x58, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x64, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x4c, 0x61, 0x74, 0x6e, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
-  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00,
-  0x78, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x58, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x66, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x4c, 0x61, 0x74, 0x6e, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
-  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
-  0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
-  0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
-  0x18, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
-  0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00
-};
-unsigned int split_de_fr_arsc_len = 1012;
diff --git a/libs/androidfw/tests/data/basic/split_hdpi_v4_arsc.h b/libs/androidfw/tests/data/basic/split_hdpi_v4_arsc.h
deleted file mode 100644
index 0cc3915..0000000
--- a/libs/androidfw/tests/data/basic/split_hdpi_v4_arsc.h
+++ /dev/null
@@ -1,69 +0,0 @@
-unsigned char split_hdpi_v4_arsc[] = {
-  0x02, 0x00, 0x0c, 0x00, 0x10, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x1c, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x68, 0x00,
-  0x64, 0x00, 0x70, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01,
-  0xd8, 0x02, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00,
-  0x6d, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00,
-  0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00,
-  0x73, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00,
-  0x69, 0x00, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x20, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
-  0x90, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
-  0x2c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00,
-  0x06, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00, 0x6f, 0x00, 0x75, 0x00,
-  0x74, 0x00, 0x00, 0x00, 0x06, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00,
-  0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00, 0x07, 0x00, 0x69, 0x00,
-  0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x72, 0x00,
-  0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00, 0x6c, 0x00,
-  0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x61, 0x00, 0x72, 0x00, 0x72, 0x00,
-  0x61, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
-  0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x64, 0x00, 0x65, 0x00, 0x6e, 0x00,
-  0x73, 0x00, 0x69, 0x00, 0x74, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
-  0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x01, 0x02, 0x4c, 0x00, 0x68, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
-  0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
-  0x18, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
-  0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00
-};
-unsigned int split_hdpi_v4_arsc_len = 784;
diff --git a/libs/androidfw/tests/data/basic/split_xhdpi_v4_arsc.h b/libs/androidfw/tests/data/basic/split_xhdpi_v4_arsc.h
deleted file mode 100644
index d44ba96..0000000
--- a/libs/androidfw/tests/data/basic/split_xhdpi_v4_arsc.h
+++ /dev/null
@@ -1,69 +0,0 @@
-unsigned char split_xhdpi_v4_arsc[] = {
-  0x02, 0x00, 0x0c, 0x00, 0x14, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x1c, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x78, 0x00,
-  0x68, 0x00, 0x64, 0x00, 0x70, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x02, 0x20, 0x01, 0xd8, 0x02, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
-  0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x6e, 0x00,
-  0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2e, 0x00,
-  0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x62, 0x00,
-  0x61, 0x00, 0x73, 0x00, 0x69, 0x00, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
-  0xb0, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x1c, 0x00, 0x90, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
-  0x1c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
-  0x4c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00,
-  0x72, 0x00, 0x00, 0x00, 0x06, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00,
-  0x6f, 0x00, 0x75, 0x00, 0x74, 0x00, 0x00, 0x00, 0x06, 0x00, 0x73, 0x00,
-  0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00,
-  0x07, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x67, 0x00,
-  0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00,
-  0x79, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x61, 0x00,
-  0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x1c, 0x00, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x64, 0x00,
-  0x65, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x74, 0x00, 0x79, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x02, 0x10, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00, 0x68, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00,
-  0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-unsigned int split_xhdpi_v4_arsc_len = 788;
diff --git a/libs/androidfw/tests/data/basic/split_xxhdpi_v4_arsc.h b/libs/androidfw/tests/data/basic/split_xxhdpi_v4_arsc.h
deleted file mode 100644
index 2f3f682..0000000
--- a/libs/androidfw/tests/data/basic/split_xxhdpi_v4_arsc.h
+++ /dev/null
@@ -1,69 +0,0 @@
-unsigned char split_xxhdpi_v4_arsc[] = {
-  0x02, 0x00, 0x0c, 0x00, 0x14, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x1c, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x78, 0x00,
-  0x78, 0x00, 0x68, 0x00, 0x64, 0x00, 0x70, 0x00, 0x69, 0x00, 0x00, 0x00,
-  0x00, 0x02, 0x20, 0x01, 0xd8, 0x02, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
-  0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x6e, 0x00,
-  0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2e, 0x00,
-  0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x62, 0x00,
-  0x61, 0x00, 0x73, 0x00, 0x69, 0x00, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
-  0xb0, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x1c, 0x00, 0x90, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
-  0x1c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
-  0x4c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00,
-  0x72, 0x00, 0x00, 0x00, 0x06, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00,
-  0x6f, 0x00, 0x75, 0x00, 0x74, 0x00, 0x00, 0x00, 0x06, 0x00, 0x73, 0x00,
-  0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00,
-  0x07, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x67, 0x00,
-  0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00,
-  0x79, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x61, 0x00,
-  0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x1c, 0x00, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x64, 0x00,
-  0x65, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x74, 0x00, 0x79, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x02, 0x10, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00, 0x68, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00,
-  0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-unsigned int split_xxhdpi_v4_arsc_len = 788;
diff --git a/libs/androidfw/tests/data/feature/AndroidManifest.xml b/libs/androidfw/tests/data/feature/AndroidManifest.xml
index c2343b7..c972372 100644
--- a/libs/androidfw/tests/data/feature/AndroidManifest.xml
+++ b/libs/androidfw/tests/data/feature/AndroidManifest.xml
@@ -15,5 +15,5 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.test.basic">
+    package="com.android.basic">
 </manifest>
diff --git a/libs/androidfw/tests/data/feature/build b/libs/androidfw/tests/data/feature/build
index 0f3307f..3316e41 100755
--- a/libs/androidfw/tests/data/feature/build
+++ b/libs/androidfw/tests/data/feature/build
@@ -15,7 +15,6 @@
 # limitations under the License.
 #
 
-aapt package -M AndroidManifest.xml -S res --feature-of ../basic/bundle.apk -F bundle.apk -f && \
-unzip bundle.apk resources.arsc && \
-mv resources.arsc feature.arsc && \
-xxd -i feature.arsc > feature_arsc.h
+set -e
+
+aapt package -M AndroidManifest.xml -S res --feature-of ../basic/basic.apk -F feature.apk -f
diff --git a/libs/androidfw/tests/data/feature/feature.apk b/libs/androidfw/tests/data/feature/feature.apk
new file mode 100644
index 0000000..1e65c27
--- /dev/null
+++ b/libs/androidfw/tests/data/feature/feature.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/feature/feature_arsc.h b/libs/androidfw/tests/data/feature/feature_arsc.h
deleted file mode 100644
index cd29910..0000000
--- a/libs/androidfw/tests/data/feature/feature_arsc.h
+++ /dev/null
@@ -1,73 +0,0 @@
-unsigned char feature_arsc[] = {
-  0x02, 0x00, 0x0c, 0x00, 0x44, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
-  0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x33, 0x00,
-  0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
-  0x34, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xf8, 0x02, 0x00, 0x00,
-  0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00,
-  0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00,
-  0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
-  0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00, 0x69, 0x00, 0x63, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
-  0x09, 0x00, 0x00, 0x00, 0xa0, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x80, 0x00, 0x00, 0x00,
-  0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
-  0x1e, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x07, 0x00, 0x3c, 0x00,
-  0x65, 0x00, 0x6d, 0x00, 0x70, 0x00, 0x74, 0x00, 0x79, 0x00, 0x3e, 0x00,
-  0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
-  0x00, 0x00, 0x06, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00,
-  0x6e, 0x00, 0x67, 0x00, 0x00, 0x00, 0x07, 0x00, 0x69, 0x00, 0x6e, 0x00,
-  0x74, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x1c, 0x00, 0x58, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
-  0x1c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00,
-  0x74, 0x00, 0x33, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00,
-  0x73, 0x00, 0x74, 0x00, 0x34, 0x00, 0x00, 0x00, 0x07, 0x00, 0x6e, 0x00,
-  0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x33, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
-  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
-  0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
-  0x6c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
-  0x14, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00,
-  0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
-  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x00, 0x10, 0xc8, 0x00, 0x00, 0x00
-};
-unsigned int feature_arsc_len = 836;
diff --git a/libs/androidfw/tests/data/lib/AndroidManifest.xml b/libs/androidfw/tests/data/lib/AndroidManifest.xml
index a56ac18..02f5d3e 100644
--- a/libs/androidfw/tests/data/lib/AndroidManifest.xml
+++ b/libs/androidfw/tests/data/lib/AndroidManifest.xml
@@ -15,7 +15,6 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.test.basic">
-    <application>
-    </application>
+    package="com.android.lib">
+    <application />
 </manifest>
diff --git a/libs/androidfw/tests/data/lib/R.h b/libs/androidfw/tests/data/lib/R.h
index 6013973..bb22d22 100644
--- a/libs/androidfw/tests/data/lib/R.h
+++ b/libs/androidfw/tests/data/lib/R.h
@@ -14,26 +14,32 @@
  * limitations under the License.
  */
 
-#ifndef __LIB_R_H
-#define __LIB_R_H
+#ifndef TEST_DATA_LIB_R_H_
+#define TEST_DATA_LIB_R_H_
 
+#include <cstdint>
+
+namespace com {
+namespace android {
 namespace lib {
-namespace R {
 
-namespace attr {
-    enum {
-        attr1       = 0x02010000, // default
-        attr2       = 0x02010001, // default
+struct R {
+  struct attr {
+    enum : uint32_t {
+      attr1 = 0x02010000,  // default
+      attr2 = 0x02010001,  // default
     };
-}
+  };
 
-namespace style {
-    enum {
-        Theme        = 0x02020000,  // default
+  struct style {
+    enum : uint32_t {
+      Theme = 0x02020000,  // default
     };
-}
+  };
+};
 
-} // namespace R
-} // namespace lib
+}  // namespace lib
+}  // namespace android
+}  // namespace com
 
-#endif // __LIB_R_H
+#endif  // TEST_DATA_R_H_
diff --git a/libs/androidfw/tests/data/lib/build b/libs/androidfw/tests/data/lib/build
index 4102903..5c3d02c 100755
--- a/libs/androidfw/tests/data/lib/build
+++ b/libs/androidfw/tests/data/lib/build
@@ -15,7 +15,6 @@
 # limitations under the License.
 #
 
-aapt package -M AndroidManifest.xml -S res -F bundle.apk -f --shared-lib && \
-unzip bundle.apk resources.arsc && \
-mv resources.arsc lib.arsc && \
-xxd -i lib.arsc > lib_arsc.h
+set -e
+
+aapt package -M AndroidManifest.xml -S res -F lib.apk -f --shared-lib
diff --git a/libs/androidfw/tests/data/lib/lib.apk b/libs/androidfw/tests/data/lib/lib.apk
new file mode 100644
index 0000000..44c27c7
--- /dev/null
+++ b/libs/androidfw/tests/data/lib/lib.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/lib/lib_arsc.h b/libs/androidfw/tests/data/lib/lib_arsc.h
deleted file mode 100644
index 62bed65..0000000
--- a/libs/androidfw/tests/data/lib/lib_arsc.h
+++ /dev/null
@@ -1,68 +0,0 @@
-unsigned char lib_arsc[] = {
-  0x02, 0x00, 0x0c, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xe4, 0x02, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00,
-  0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00,
-  0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
-  0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00, 0x69, 0x00, 0x63, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00,
-  0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00,
-  0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
-  0x54, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
-  0x05, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x31, 0x00,
-  0x00, 0x00, 0x05, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
-  0x32, 0x00, 0x00, 0x00, 0x05, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00,
-  0x6d, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
-  0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00,
-  0x8c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x54, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00,
-  0x10, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
-  0x04, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x01, 0x02, 0x4c, 0x00, 0x78, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x10, 0xbc, 0x02, 0x00, 0x00,
-  0x01, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00
-};
-unsigned int lib_arsc_len = 780;
diff --git a/libs/androidfw/tests/data/lib/res/values/values.xml b/libs/androidfw/tests/data/lib/res/values/values.xml
index ec8117a7..51e3a40 100644
--- a/libs/androidfw/tests/data/lib/res/values/values.xml
+++ b/libs/androidfw/tests/data/lib/res/values/values.xml
@@ -19,7 +19,7 @@
     <attr name="attr2" format="integer" />
 
     <style name="Theme">
-        <item name="com.android.test.basic:attr1">700</item>
-        <item name="com.android.test.basic:attr2">?com.android.test.basic:attr1</item>
+        <item name="com.android.lib:attr1">700</item>
+        <item name="com.android.lib:attr2">?com.android.lib:attr1</item>
     </style>
 </resources>
diff --git a/libs/androidfw/tests/data/overlay/build b/libs/androidfw/tests/data/overlay/build
index f737677..112f373 100755
--- a/libs/androidfw/tests/data/overlay/build
+++ b/libs/androidfw/tests/data/overlay/build
@@ -15,7 +15,6 @@
 # limitations under the License.
 #
 
-aapt package -M AndroidManifest.xml -S res -F bundle.apk -f && \
-unzip bundle.apk resources.arsc && \
-mv resources.arsc overlay.arsc && \
-xxd -i overlay.arsc > overlay_arsc.h
+set -e
+
+aapt package -M AndroidManifest.xml -S res -F overlay.apk -f
diff --git a/libs/androidfw/tests/data/overlay/overlay.apk b/libs/androidfw/tests/data/overlay/overlay.apk
new file mode 100644
index 0000000..e0e0543
--- /dev/null
+++ b/libs/androidfw/tests/data/overlay/overlay.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/overlay/overlay_arsc.h b/libs/androidfw/tests/data/overlay/overlay_arsc.h
deleted file mode 100644
index 5bd98b2..0000000
--- a/libs/androidfw/tests/data/overlay/overlay_arsc.h
+++ /dev/null
@@ -1,69 +0,0 @@
-unsigned char overlay_arsc[] = {
-  0x02, 0x00, 0x0c, 0x00, 0x10, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x74, 0x00,
-  0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x6f, 0x00,
-  0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xc4, 0x02, 0x00, 0x00,
-  0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00,
-  0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00,
-  0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
-  0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00, 0x69, 0x00, 0x63, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x54, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00,
-  0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00, 0x06, 0x00, 0x73, 0x00,
-  0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00,
-  0x05, 0x00, 0x61, 0x00, 0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x50, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0e, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00,
-  0x74, 0x00, 0x32, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x69, 0x00, 0x6e, 0x00,
-  0x74, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x72, 0x00, 0x41, 0x00,
-  0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x31, 0x00, 0x00, 0x00,
-  0x02, 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x01, 0x02, 0x44, 0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x10, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10,
-  0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10,
-  0x0b, 0x00, 0x00, 0x00
-};
-unsigned int overlay_arsc_len = 784;
diff --git a/libs/androidfw/tests/data/styles/R.h b/libs/androidfw/tests/data/styles/R.h
index 6dc6ede..4127aa0 100644
--- a/libs/androidfw/tests/data/styles/R.h
+++ b/libs/androidfw/tests/data/styles/R.h
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TEST_DATA_STYLES_R_H_
+#define TEST_DATA_STYLES_R_H_
+
 #include <cstdint>
 
 namespace com {
@@ -17,9 +36,9 @@
   };
 
   struct string {
-      enum : uint32_t {
-          string_one = 0x7f030000u,
-      };
+    enum : uint32_t {
+      string_one = 0x7f030000u,
+    };
   };
 
   struct style {
@@ -33,3 +52,5 @@
 }  // namespace app
 }  // namespace android
 }  // namespace com
+
+#endif  // TEST_DATA_STYLES_R_H_
diff --git a/libs/androidfw/tests/data/styles/build b/libs/androidfw/tests/data/styles/build
new file mode 100755
index 0000000..81f78b1
--- /dev/null
+++ b/libs/androidfw/tests/data/styles/build
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+set -e
+
+aapt package -F styles.apk -M AndroidManifest.xml -S res -f
diff --git a/libs/androidfw/tests/data/styles/build.sh b/libs/androidfw/tests/data/styles/build.sh
deleted file mode 100755
index e763421..0000000
--- a/libs/androidfw/tests/data/styles/build.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-
-set -e
-
-aapt package -F package.apk -M AndroidManifest.xml -S res
-unzip -j package.apk resources.arsc res/layout/layout.xml
-rm package.apk
diff --git a/libs/androidfw/tests/data/styles/layout.xml b/libs/androidfw/tests/data/styles/layout.xml
deleted file mode 100644
index 4997e71..0000000
--- a/libs/androidfw/tests/data/styles/layout.xml
+++ /dev/null
Binary files differ
diff --git a/libs/androidfw/tests/data/styles/resources.arsc b/libs/androidfw/tests/data/styles/resources.arsc
deleted file mode 100644
index 8f65c9a..0000000
--- a/libs/androidfw/tests/data/styles/resources.arsc
+++ /dev/null
Binary files differ
diff --git a/libs/androidfw/tests/data/styles/styles.apk b/libs/androidfw/tests/data/styles/styles.apk
new file mode 100644
index 0000000..6064c48
--- /dev/null
+++ b/libs/androidfw/tests/data/styles/styles.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/system/R.h b/libs/androidfw/tests/data/system/R.h
index 6a31fb8..becb388 100644
--- a/libs/androidfw/tests/data/system/R.h
+++ b/libs/androidfw/tests/data/system/R.h
@@ -14,32 +14,34 @@
  * limitations under the License.
  */
 
-#ifndef __ANDROID_R_H
-#define __ANDROID_R_H
+#ifndef TEST_DATA_SYSTEM_R_H_
+#define TEST_DATA_SYSTEM_R_H_
+
+#include <cstdint>
 
 namespace android {
-namespace R {
 
-namespace attr {
-    enum {
-        background  = 0x01010000, // default
-        foreground  = 0x01010001, // default
+struct R {
+  struct attr {
+    enum : uint32_t {
+      background = 0x01010000,  // default
+      foreground = 0x01010001,  // default
     };
-}
+  };
 
-namespace style {
-    enum {
-        Theme_One      = 0x01020000,   // default
+  struct style {
+    enum : uint32_t {
+      Theme_One = 0x01020000,  // default
     };
-}
+  };
 
-namespace integer {
-    enum {
-        number = 0x01030000, // sv
+  struct integer {
+    enum : uint32_t {
+      number = 0x01030000,  // sv
     };
-}
+  };
+};
 
-} // namespace R
-} // namespace android
+}  // namespace android
 
-#endif // __ANDROID_R_H
+#endif  // TEST_DATA_SYSTEM_R_H_
diff --git a/libs/androidfw/tests/data/system/build b/libs/androidfw/tests/data/system/build
index 1a70e84..bfbdf4c 100755
--- a/libs/androidfw/tests/data/system/build
+++ b/libs/androidfw/tests/data/system/build
@@ -15,7 +15,6 @@
 # limitations under the License.
 #
 
-aapt package -x -M AndroidManifest.xml -S res -F bundle.apk -f && \
-unzip bundle.apk resources.arsc && \
-mv resources.arsc system.arsc && \
-xxd -i system.arsc > system_arsc.h
+set -e
+
+aapt package -x -M AndroidManifest.xml -S res -F system.apk -f
diff --git a/libs/androidfw/tests/data/system/system.apk b/libs/androidfw/tests/data/system/system.apk
new file mode 100644
index 0000000..1299016
--- /dev/null
+++ b/libs/androidfw/tests/data/system/system.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/system/system_arsc.h b/libs/androidfw/tests/data/system/system_arsc.h
deleted file mode 100644
index b0dab6b..0000000
--- a/libs/androidfw/tests/data/system/system_arsc.h
+++ /dev/null
@@ -1,88 +0,0 @@
-unsigned char system_arsc[] = {
-  0x02, 0x00, 0x0c, 0x00, 0xf8, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xd0, 0x03, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00,
-  0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x78, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0c, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00,
-  0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x65, 0x00,
-  0x00, 0x00, 0x07, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00,
-  0x67, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x5e, 0x00,
-  0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x2d, 0x00, 0x70, 0x00,
-  0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x84, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00,
-  0x0a, 0x00, 0x62, 0x00, 0x61, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x67, 0x00,
-  0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00,
-  0x0a, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00, 0x67, 0x00,
-  0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00,
-  0x09, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00,
-  0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x06, 0x00,
-  0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
-  0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00, 0x8c, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
-  0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x08, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00,
-  0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00,
-  0x78, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x50, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
-  0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x01, 0x01,
-  0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xff, 0x02, 0x02, 0x10, 0x00,
-  0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00, 0x60, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
-  0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x76, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10,
-  0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-unsigned int system_arsc_len = 1016;
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/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 5e21dfc..6786a69 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -52,16 +52,20 @@
 SkiaCanvas::SkiaCanvas() {}
 
 SkiaCanvas::SkiaCanvas(SkCanvas* canvas)
-    : mCanvas(SkRef(canvas)) {}
+    : mCanvas(canvas) {}
 
 SkiaCanvas::SkiaCanvas(const SkBitmap& bitmap) {
-    mCanvas.reset(new SkCanvas(bitmap));
+    mCanvasOwned = std::unique_ptr<SkCanvas>(new SkCanvas(bitmap));
+    mCanvas = mCanvasOwned.get();
 }
 
 SkiaCanvas::~SkiaCanvas() {}
 
 void SkiaCanvas::reset(SkCanvas* skiaCanvas) {
-    mCanvas.reset(SkRef(skiaCanvas));
+    if (mCanvas != skiaCanvas) {
+        mCanvas = skiaCanvas;
+        mCanvasOwned.reset();
+    }
     mSaveStack.reset(nullptr);
     mHighContrastText = false;
 }
@@ -99,8 +103,9 @@
         mCanvas->replayClips(&copier);
     }
 
-    // unrefs the existing canvas
-    mCanvas.reset(newCanvas);
+    // deletes the previously owned canvas (if any)
+    mCanvasOwned = std::unique_ptr<SkCanvas>(newCanvas);
+    mCanvas = newCanvas;
 
     // clean up the old save stack
     mSaveStack.reset(nullptr);
@@ -307,7 +312,7 @@
     const SkMatrix saveMatrix = mCanvas->getTotalMatrix();
 
     for (auto clip = begin; clip != end; ++clip) {
-        clip->apply(mCanvas.get());
+        clip->apply(mCanvas);
     }
 
     mCanvas->setMatrix(saveMatrix);
@@ -562,7 +567,7 @@
 void SkiaCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix, const SkPaint* paint) {
     SkBitmap bitmap;
     hwuiBitmap.getSkBitmap(&bitmap);
-    SkAutoCanvasRestore acr(mCanvas.get(), true);
+    SkAutoCanvasRestore acr(mCanvas, true);
     mCanvas->concat(matrix);
     mCanvas->drawBitmap(bitmap, 0, 0, paint);
 }
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index a0cdfcb..4f1d857 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -35,15 +35,15 @@
      *  Create a new SkiaCanvas.
      *
      *  @param canvas SkCanvas to handle calls made to this SkiaCanvas. Must
-     *      not be NULL. This constructor will ref() the SkCanvas, and unref()
-     *      it in its destructor.
+     *      not be NULL. This constructor does not take ownership, so the caller
+     *      must guarantee that it remains valid while the SkiaCanvas is valid.
      */
     explicit SkiaCanvas(SkCanvas* canvas);
 
     virtual ~SkiaCanvas();
 
     virtual SkCanvas* asSkCanvas() override {
-        return mCanvas.get();
+        return mCanvas;
     }
 
     virtual void resetRecording(int width, int height,
@@ -182,7 +182,9 @@
 
     class Clip;
 
-    sk_sp<SkCanvas>          mCanvas;
+    std::unique_ptr<SkCanvas> mCanvasOwned; // might own a canvas we allocated
+    SkCanvas*                 mCanvas;    // we do NOT own this canvas, it must survive us
+                                          // unless it is the same as mCanvasOwned.get()
     std::unique_ptr<SkDeque> mSaveStack; // lazily allocated, tracks partial saves.
     std::vector<Clip>        mClipStack; // tracks persistent clips.
 };
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/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 6df544f..95db258 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -32,7 +32,6 @@
 
 void SkiaRecordingCanvas::initDisplayList(uirenderer::RenderNode* renderNode, int width,
         int height) {
-    mBarrierPending = false;
     mCurrentBarrier = nullptr;
     SkASSERT(mDisplayList.get() == nullptr);
 
@@ -76,8 +75,6 @@
 }
 
 void SkiaRecordingCanvas::insertReorderBarrier(bool enableReorder) {
-    mBarrierPending = enableReorder;
-
     if (nullptr != mCurrentBarrier) {
         // finish off the existing chunk
         SkDrawable* drawable =
@@ -86,6 +83,12 @@
         mCurrentBarrier = nullptr;
         drawDrawable(drawable);
     }
+    if (enableReorder) {
+        mCurrentBarrier = (StartReorderBarrierDrawable*)
+                mDisplayList->allocateDrawable<StartReorderBarrierDrawable>(
+                mDisplayList.get());
+        drawDrawable(mCurrentBarrier);
+    }
 }
 
 void SkiaRecordingCanvas::drawLayer(uirenderer::DeferredLayerUpdater* layerUpdater) {
@@ -97,15 +100,6 @@
 }
 
 void SkiaRecordingCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) {
-    // lazily create the chunk if needed
-    if (mBarrierPending) {
-        mCurrentBarrier = (StartReorderBarrierDrawable*)
-                mDisplayList->allocateDrawable<StartReorderBarrierDrawable>(
-                mDisplayList.get());
-        drawDrawable(mCurrentBarrier);
-        mBarrierPending = false;
-    }
-
     // record the child node
     mDisplayList->mChildNodes.emplace_back(renderNode, asSkCanvas(), true, mCurrentBarrier);
     auto& renderNodeDrawable = mDisplayList->mChildNodes.back();
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index 8aef97f..10829f8 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -76,7 +76,6 @@
 private:
     SkLiteRecorder mRecorder;
     std::unique_ptr<SkiaDisplayList> mDisplayList;
-    bool mBarrierPending;
     StartReorderBarrierDrawable* mCurrentBarrier;
 
     /**
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
index 177a729..9dc2b59 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.cpp
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -88,7 +88,7 @@
     caches.tessellationCache.trim();
 
 #if DEBUG_MEMORY_USAGE
-    mCaches.dumpMemoryUsage();
+    caches.dumpMemoryUsage();
 #else
     if (CC_UNLIKELY(Properties::debugLevel & kDebugMemory)) {
         caches.dumpMemoryUsage();
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 8c956e5..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);
@@ -1542,6 +1544,14 @@
         canvas.insertReorderBarrier(false);
         drawOrderedRect(&canvas, 8);
         drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
+        canvas.insertReorderBarrier(true); //reorder a node ahead of drawrect op
+        drawOrderedRect(&canvas, 11);
+        drawOrderedNode(&canvas, 10, -1.0f);
+        canvas.insertReorderBarrier(false);
+        canvas.insertReorderBarrier(true); //test with two empty reorder sections
+        canvas.insertReorderBarrier(true);
+        canvas.insertReorderBarrier(false);
+        drawOrderedRect(&canvas, 12);
     });
     FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
             sLightGeometry, Caches::getInstance());
@@ -1549,7 +1559,7 @@
 
     ZReorderTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
-    EXPECT_EQ(10, renderer.getIndex());
+    EXPECT_EQ(13, renderer.getIndex());
 };
 
 RENDERTHREAD_TEST(FrameBuilder, projectionReorder) {
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 ae4f0f4..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);
@@ -114,13 +116,21 @@
         canvas.insertReorderBarrier(false);
         drawOrderedRect(&canvas, 8);
         drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
+        canvas.insertReorderBarrier(true); //reorder a node ahead of drawrect op
+        drawOrderedRect(&canvas, 11);
+        drawOrderedNode(&canvas, 10, -1.0f);
+        canvas.insertReorderBarrier(false);
+        canvas.insertReorderBarrier(true); //test with two empty reorder sections
+        canvas.insertReorderBarrier(true);
+        canvas.insertReorderBarrier(false);
+        drawOrderedRect(&canvas, 12);
     });
 
     //create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
     ZReorderCanvas canvas(100, 100);
     RenderNodeDrawable drawable(parent.get(), &canvas, false);
     canvas.drawDrawable(&drawable);
-    EXPECT_EQ(10, canvas.getIndex());
+    EXPECT_EQ(13, canvas.getIndex());
 }
 
 TEST(RenderNodeDrawable, composeOnLayer)
@@ -303,40 +313,42 @@
     static const int LAYER_HEIGHT = 200;
     class ProjectionTestCanvas : public SkCanvas {
     public:
-        ProjectionTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {}
+        ProjectionTestCanvas(int* drawCounter)
+            : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT)
+            , mDrawCounter(drawCounter) 
+        {}
         void onDrawArc(const SkRect&, SkScalar startAngle, SkScalar sweepAngle, bool useCenter,
                 const SkPaint&) override {
-            EXPECT_EQ(0, mIndex++); //part of painting the layer
+            EXPECT_EQ(0, (*mDrawCounter)++); //part of painting the layer
             EXPECT_EQ(SkRect::MakeLTRB(0, 0, LAYER_WIDTH, LAYER_HEIGHT), getBounds(this));
         }
         void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
-            EXPECT_EQ(1, mIndex++);
+            EXPECT_EQ(1, (*mDrawCounter)++);
             EXPECT_EQ(SkRect::MakeLTRB(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT), getBounds(this));
         }
         void onDrawOval(const SkRect&, const SkPaint&) override {
-            EXPECT_EQ(2, mIndex++);
+            EXPECT_EQ(2, (*mDrawCounter)++);
             SkMatrix expectedMatrix;
             expectedMatrix.setTranslate(100 - SCROLL_X, 100 - SCROLL_Y);
             EXPECT_EQ(expectedMatrix, getTotalMatrix());
             EXPECT_EQ(SkRect::MakeLTRB(-85, -80, 295, 300), getLocalBounds(this));
         }
-        int mIndex = 0;
+        int* mDrawCounter;
     };
 
     class ProjectionLayer : public SkSurface_Base {
     public:
-        ProjectionLayer(ProjectionTestCanvas *canvas)
+        ProjectionLayer(int* drawCounter)
             : SkSurface_Base(SkImageInfo::MakeN32Premul(LAYER_WIDTH, LAYER_HEIGHT), nullptr)
-            , mCanvas(canvas) {
+            , mDrawCounter(drawCounter) {
         }
         void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) override {
-            EXPECT_EQ(3, mCanvas->mIndex++);
+            EXPECT_EQ(3, (*mDrawCounter)++);
             EXPECT_EQ(SkRect::MakeLTRB(100 - SCROLL_X, 100 - SCROLL_Y, 300 - SCROLL_X,
-                   300 - SCROLL_Y), getBounds(mCanvas));
+                   300 - SCROLL_Y), getBounds(this->getCanvas()));
         }
         SkCanvas* onNewCanvas() override {
-            mCanvas->ref();
-            return mCanvas;
+            return new ProjectionTestCanvas(mDrawCounter);
         }
         sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override {
             return sk_sp<SkSurface>();
@@ -345,7 +357,7 @@
             return sk_sp<SkImage>();
         }
         void onCopyOnWrite(ContentChangeMode) override {}
-        ProjectionTestCanvas* mCanvas;
+        int* mDrawCounter;
     };
 
     auto receiverBackground = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
@@ -389,10 +401,10 @@
     info.observer = nullptr;
     parent->prepareTree(info);
 
-    sk_sp<ProjectionTestCanvas> canvas(new ProjectionTestCanvas());
+    int drawCounter = 0;
     //set a layer after prepareTree to avoid layer logic there
     child->animatorProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
-    sk_sp<SkSurface> surfaceLayer1(new ProjectionLayer(canvas.get()));
+    sk_sp<SkSurface> surfaceLayer1(new ProjectionLayer(&drawCounter));
     child->setLayerSurface(surfaceLayer1);
     Matrix4 windowTransform;
     windowTransform.loadTranslate(100, 100, 0);
@@ -402,11 +414,11 @@
     layerUpdateQueue.enqueueLayerWithDamage(child.get(),
             android::uirenderer::Rect(LAYER_WIDTH, LAYER_HEIGHT));
     SkiaPipeline::renderLayersImpl(layerUpdateQueue, true);
-    EXPECT_EQ(1, canvas->mIndex);  //assert index 0 is drawn on the layer
+    EXPECT_EQ(1, drawCounter);  //assert index 0 is drawn on the layer
 
-    RenderNodeDrawable drawable(parent.get(), canvas.get(), true);
-    canvas->drawDrawable(&drawable);
-    EXPECT_EQ(4, canvas->mIndex);
+    RenderNodeDrawable drawable(parent.get(), surfaceLayer1->getCanvas(), true);
+    surfaceLayer1->getCanvas()->drawDrawable(&drawable);
+    EXPECT_EQ(4, drawCounter);
 
     // clean up layer pointer, so we can safely destruct RenderNode
     child->setLayerSurface(nullptr);
@@ -479,7 +491,7 @@
     info.observer = nullptr;
     parent->prepareTree(info);
 
-    sk_sp<ProjectionChildScrollTestCanvas> canvas(new ProjectionChildScrollTestCanvas());
+    std::unique_ptr<ProjectionChildScrollTestCanvas> canvas(new ProjectionChildScrollTestCanvas());
     RenderNodeDrawable drawable(parent.get(), canvas.get(), true);
     canvas->drawDrawable(&drawable);
     EXPECT_EQ(2, canvas->mIndex);
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/AudioManager.java b/media/java/android/media/AudioManager.java
index 435e6ba..65eadb6 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -801,8 +801,8 @@
      * management of audio settings or the main telephony application.
      *
      * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
-     * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC} or
-     * {@link #STREAM_ALARM}
+     * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
+     * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
      * @param direction The direction to adjust the volume. One of
      *            {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
      *            {@link #ADJUST_SAME}.
@@ -3195,7 +3195,8 @@
      *            {@link #STREAM_MUSIC},
      *            {@link #STREAM_ALARM},
      *            {@link #STREAM_NOTIFICATION},
-     *            {@link #STREAM_DTMF}.
+     *            {@link #STREAM_DTMF},
+     *            {@link #STREAM_ACCESSIBILITY}.
      *
      * @return The bit-mask "or" of audio output device codes for all enabled devices on this
      *         stream. Zero or more of
@@ -3238,6 +3239,7 @@
         case STREAM_ALARM:
         case STREAM_NOTIFICATION:
         case STREAM_DTMF:
+        case STREAM_ACCESSIBILITY:
             return AudioSystem.getDevicesForStream(streamType);
         default:
             return 0;
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/IVolumeController.aidl b/media/java/android/media/IVolumeController.aidl
index 90ac416..7f37265 100644
--- a/media/java/android/media/IVolumeController.aidl
+++ b/media/java/android/media/IVolumeController.aidl
@@ -32,4 +32,11 @@
     void setLayoutDirection(int layoutDirection);
 
     void dismiss();
+
+    /**
+     * Change the a11y mode.
+     * @param a11yMode one of {@link VolumePolicy#A11Y_MODE_MEDIA_A11Y_VOLUME},
+     *     {@link VolumePolicy#A11Y_MODE_INDEPENDENT_A11Y_VOLUME}
+     */
+    void setA11yMode(int mode);
 }
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/java/android/media/VolumePolicy.java b/media/java/android/media/VolumePolicy.java
index 1d33128..bbcce82 100644
--- a/media/java/android/media/VolumePolicy.java
+++ b/media/java/android/media/VolumePolicy.java
@@ -25,6 +25,17 @@
 public final class VolumePolicy implements Parcelable {
     public static final VolumePolicy DEFAULT = new VolumePolicy(false, false, true, 400);
 
+    /**
+     * Accessibility volume policy where the STREAM_MUSIC volume (i.e. media volume) affects
+     * the STREAM_ACCESSIBILITY volume, and vice-versa.
+     */
+    public static final int A11Y_MODE_MEDIA_A11Y_VOLUME = 0;
+    /**
+     * Accessibility volume policy where the STREAM_ACCESSIBILITY volume is independent from
+     * any other volume.
+     */
+    public static final int A11Y_MODE_INDEPENDENT_A11Y_VOLUME = 1;
+
     /** Allow volume adjustments lower from vibrate to enter ringer mode = silent */
     public final boolean volumeDownToEnterSilent;
 
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 96c12dd..4de1d00 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -607,8 +607,6 @@
 
     gFields.cryptoInfoSetID =
         env->GetMethodID(clazz, "set", "(I[I[I[B[BI)V");
-
-    DataSource::RegisterDefaultSniffers();
 }
 
 static void android_media_MediaExtractor_native_setup(
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/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index 94286ec..5aa673b 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -44,6 +44,7 @@
     protected View mEcaView;
     protected boolean mEnableHaptics;
     private boolean mDismissing;
+    private CountDownTimer mCountdownTimer = null;
 
     // To avoid accidental lockout due to events while the device in in the pocket, ignore
     // any passwords with length less than or equal to this length.
@@ -215,11 +216,13 @@
     protected void handleAttemptLockout(long elapsedRealtimeDeadline) {
         setPasswordEntryEnabled(false);
         long elapsedRealtime = SystemClock.elapsedRealtime();
-        new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) {
+        long secondsInFuture = (long) Math.ceil(
+                (elapsedRealtimeDeadline - elapsedRealtime) / 1000.0);
+        mCountdownTimer = new CountDownTimer(secondsInFuture * 1000, 1000) {
 
             @Override
             public void onTick(long millisUntilFinished) {
-                int secondsRemaining = (int) (millisUntilFinished / 1000);
+                int secondsRemaining = (int) Math.round(millisUntilFinished / 1000.0);
                 mSecurityMessageDisplay.formatMessage(
                         R.string.kg_too_many_failed_attempts_countdown, secondsRemaining);
             }
@@ -252,6 +255,10 @@
 
     @Override
     public void onPause() {
+        if (mCountdownTimer != null) {
+            mCountdownTimer.cancel();
+            mCountdownTimer = null;
+        }
         if (mPendingLockCheck != null) {
             mPendingLockCheck.cancel(false);
             mPendingLockCheck = null;
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index 330632b..c2b57ff 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -325,12 +325,13 @@
         mLockPatternView.clearPattern();
         mLockPatternView.setEnabled(false);
         final long elapsedRealtime = SystemClock.elapsedRealtime();
-
-        mCountdownTimer = new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) {
+        final long secondsInFuture = (long) Math.ceil(
+                (elapsedRealtimeDeadline - elapsedRealtime) / 1000.0);
+        mCountdownTimer = new CountDownTimer(secondsInFuture * 1000, 1000) {
 
             @Override
             public void onTick(long millisUntilFinished) {
-                final int secondsRemaining = (int) (millisUntilFinished / 1000);
+                final int secondsRemaining = (int) Math.round(millisUntilFinished / 1000.0);
                 mSecurityMessageDisplay.formatMessage(
                         R.string.kg_too_many_failed_attempts_countdown, secondsRemaining);
             }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index cdcc05c..0a7bdbf 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -26,6 +26,7 @@
 import static android.os.BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE;
 import static android.os.BatteryManager.EXTRA_PLUGGED;
 import static android.os.BatteryManager.EXTRA_STATUS;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
 
 import android.app.ActivityManager;
 import android.app.AlarmManager;
@@ -191,8 +192,6 @@
     // Password attempts
     private SparseIntArray mFailedAttempts = new SparseIntArray();
 
-    /** Tracks whether strong authentication hasn't been used since quite some time per user. */
-    private ArraySet<Integer> mStrongAuthNotTimedOut = new ArraySet<>();
     private final StrongAuthTracker mStrongAuthTracker;
 
     private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
@@ -209,6 +208,7 @@
     private TrustManager mTrustManager;
     private UserManager mUserManager;
     private int mFingerprintRunningState = FINGERPRINT_STATE_STOPPED;
+    private LockPatternUtils mLockPatternUtils;
 
     private final Handler mHandler = new Handler() {
         @Override
@@ -576,8 +576,7 @@
     }
 
     public boolean isUnlockingWithFingerprintAllowed() {
-        return mStrongAuthTracker.isUnlockingWithFingerprintAllowed()
-                && !hasFingerprintUnlockTimedOut(sCurrentUser);
+        return mStrongAuthTracker.isUnlockingWithFingerprintAllowed();
     }
 
     public boolean needsSlowUnlockTransition() {
@@ -588,16 +587,7 @@
         return mStrongAuthTracker;
     }
 
-    /**
-     * @return true if the user hasn't use strong authentication (pattern, PIN, password) since a
-     *         while and thus can't unlock with fingerprint, false otherwise
-     */
-    public boolean hasFingerprintUnlockTimedOut(int userId) {
-        return !mStrongAuthNotTimedOut.contains(userId);
-    }
-
     public void reportSuccessfulStrongAuthUnlockAttempt() {
-        mStrongAuthNotTimedOut.add(sCurrentUser);
         scheduleStrongAuthTimeout();
         if (mFpm != null) {
             byte[] token = null; /* TODO: pass real auth token once fp HAL supports it */
@@ -738,7 +728,7 @@
         public void onReceive(Context context, Intent intent) {
             if (ACTION_STRONG_AUTH_TIMEOUT.equals(intent.getAction())) {
                 int userId = intent.getIntExtra(USER_ID, -1);
-                mStrongAuthNotTimedOut.remove(userId);
+                mLockPatternUtils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_TIMEOUT, userId);
                 notifyStrongAuthStateChanged(userId);
             }
         }
@@ -1110,7 +1100,8 @@
                 PERMISSION_SELF, null /* handler */);
         mTrustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE);
         mTrustManager.registerTrustListener(this);
-        new LockPatternUtils(context).registerStrongAuthTracker(mStrongAuthTracker);
+        mLockPatternUtils = new LockPatternUtils(context);
+        mLockPatternUtils.registerStrongAuthTracker(mStrongAuthTracker);
 
         if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
             mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
@@ -1839,7 +1830,6 @@
             pw.println("    disabled(DPM)=" + isFingerprintDisabled(userId));
             pw.println("    possible=" + isUnlockWithFingerprintPossible(userId));
             pw.println("    strongAuthFlags=" + Integer.toHexString(strongAuthFlags));
-            pw.println("    timedout=" + hasFingerprintUnlockTimedOut(userId));
             pw.println("    trustManaged=" + getUserTrustIsManaged(userId));
         }
     }
diff --git a/packages/MtpDocumentsProvider/res/values-in/strings.xml b/packages/MtpDocumentsProvider/res/values-in/strings.xml
index 905daec..6f65337 100644
--- a/packages/MtpDocumentsProvider/res/values-in/strings.xml
+++ b/packages/MtpDocumentsProvider/res/values-in/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="6271216747302322594">"Host MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Unduhan"</string>
+    <string name="downloads_app_label" msgid="7120690641874849726">"Download"</string>
     <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
     <string name="accessing_notification_title" msgid="3030133609230917944">"Mengakses file dari <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
     <string name="error_busy_device" msgid="3997316850357386589">"Perangkat lainnya sedang sibuk. Anda dapat mentransfer file jika telah tersedia."</string>
diff --git a/packages/MtpDocumentsProvider/res/values-uz-rUZ/strings.xml b/packages/MtpDocumentsProvider/res/values-uz-rUZ/strings.xml
index dea4cff..c511172 100644
--- a/packages/MtpDocumentsProvider/res/values-uz-rUZ/strings.xml
+++ b/packages/MtpDocumentsProvider/res/values-uz-rUZ/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="6271216747302322594">"MTP Host"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Yuklanishlar"</string>
+    <string name="downloads_app_label" msgid="7120690641874849726">"Yuklanmalar"</string>
     <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g><xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
     <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> qurilmasidan fayllar o‘qilmoqda"</string>
     <string name="error_busy_device" msgid="3997316850357386589">"Ulangan qurilma band. U bo‘shamaguncha fayllarni o‘tkazib bo‘lmaydi."</string>
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-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 34d236b..fcda1d1 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Gepasmaak (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Hulp en terugvoer"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Kieslys"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"MGT"</string>
 </resources>
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-az-rAZ/strings.xml b/packages/SettingsLib/res/values-az-rAZ/strings.xml
index c0b776e..a53e97a 100644
--- a/packages/SettingsLib/res/values-az-rAZ/strings.xml
+++ b/packages/SettingsLib/res/values-az-rAZ/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Fərdi (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Yardım və rəy"</string>
     <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/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-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 23adb5a..b32388e 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_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-bn-rBD/strings.xml b/packages/SettingsLib/res/values-bn-rBD/strings.xml
index 09988ed..3ee2642e 100644
--- a/packages/SettingsLib/res/values-bn-rBD/strings.xml
+++ b/packages/SettingsLib/res/values-bn-rBD/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_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-bs-rBA/strings.xml b/packages/SettingsLib/res/values-bs-rBA/strings.xml
index 561af92..b207129 100644
--- a/packages/SettingsLib/res/values-bs-rBA/strings.xml
+++ b/packages/SettingsLib/res/values-bs-rBA/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagodi (<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-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-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 5276b3a..159a939 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Vlastní (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Nápověda a zpětná vazba"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Nabídka"</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-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 0c56b8d..49f1899 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tilpasset (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Hjælp og 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-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 60f373b..95ac313 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Benutzerdefiniert (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Hilfe &amp; Feedback"</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-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index e0b5bb7..9127b2a 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Ayuda y comentarios"</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-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-et-rEE/strings.xml b/packages/SettingsLib/res/values-et-rEE/strings.xml
index 7d70efe..f979db8 100644
--- a/packages/SettingsLib/res/values-et-rEE/strings.xml
+++ b/packages/SettingsLib/res/values-et-rEE/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Kohandatud (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Abi ja tagasiside"</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-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index e998b69..4a741f07 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_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-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-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index e2eb10d..afd343c 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personnalisée (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Aide et commentaires"</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-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 282ae4a..4d9d90c 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personnalisé (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Aide et commentaires"</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-gl-rES/strings.xml b/packages/SettingsLib/res/values-gl-rES/strings.xml
index f4bb7ad..1110fe2 100644
--- a/packages/SettingsLib/res/values-gl-rES/strings.xml
+++ b/packages/SettingsLib/res/values-gl-rES/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Axuda e suxestións"</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-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-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index a2a6e04..eefdff1 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_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-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 76f04bd..9b38b61 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagođeno (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Pomoć i povratne informacije"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Izbornik"</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-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index f5f6916..a373545 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Egyéni (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Súgó és visszajelzés"</string>
     <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-hy-rAM/arrays.xml b/packages/SettingsLib/res/values-hy-rAM/arrays.xml
index 44cfe92..1241bee 100644
--- a/packages/SettingsLib/res/values-hy-rAM/arrays.xml
+++ b/packages/SettingsLib/res/values-hy-rAM/arrays.xml
@@ -25,7 +25,7 @@
     <item msgid="8934131797783724664">"Սկանավորում…"</item>
     <item msgid="8513729475867537913">"Միանում է..."</item>
     <item msgid="515055375277271756">"Նույնականացում…"</item>
-    <item msgid="1943354004029184381">"IP հասցեն գտնվում է...."</item>
+    <item msgid="1943354004029184381">"IP հասցեի ստացում…"</item>
     <item msgid="4221763391123233270">"Միացված է"</item>
     <item msgid="624838831631122137">"Կասեցված է"</item>
     <item msgid="7979680559596111948">"Անջատվում է…"</item>
@@ -43,7 +43,7 @@
     <item msgid="8937994881315223448">"Միացված է <xliff:g id="NETWORK_NAME">%1$s</xliff:g>-ին"</item>
     <item msgid="1330262655415760617">"Անջատված"</item>
     <item msgid="7698638434317271902">"Անջատվում է <xliff:g id="NETWORK_NAME">%1$s</xliff:g>-ից…"</item>
-    <item msgid="197508606402264311">"Անջատված"</item>
+    <item msgid="197508606402264311">"Անջատած է"</item>
     <item msgid="8578370891960825148">"Անհաջող"</item>
     <item msgid="5660739516542454527">"Արգելափակված"</item>
     <item msgid="1805837518286731242">"Վատ ցանցից ժամանակավոր խուսափում"</item>
diff --git a/packages/SettingsLib/res/values-hy-rAM/strings.xml b/packages/SettingsLib/res/values-hy-rAM/strings.xml
index 6dcb745..03bac7a 100644
--- a/packages/SettingsLib/res/values-hy-rAM/strings.xml
+++ b/packages/SettingsLib/res/values-hy-rAM/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_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-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 2ee38ef..aa3dc13 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_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-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 8b2d784..f760d93 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -343,6 +343,5 @@
     <string name="screen_zoom_summary_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-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-kk-rKZ/strings.xml b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
index 92d7783..920b810 100644
--- a/packages/SettingsLib/res/values-kk-rKZ/strings.xml
+++ b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_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">"Mәзір"</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-km-rKH/strings.xml b/packages/SettingsLib/res/values-km-rKH/strings.xml
index 46cc6ce..d162bd1 100644
--- a/packages/SettingsLib/res/values-km-rKH/strings.xml
+++ b/packages/SettingsLib/res/values-km-rKH/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_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-kn-rIN/strings.xml b/packages/SettingsLib/res/values-kn-rIN/strings.xml
index cf8f382..ca0ba0a 100644
--- a/packages/SettingsLib/res/values-kn-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-kn-rIN/strings.xml
@@ -155,7 +155,7 @@
     <string name="keep_screen_on" msgid="1146389631208760344">"ಎಚ್ಚರವಾಗಿರು"</string>
     <string name="keep_screen_on_summary" msgid="2173114350754293009">"ಚಾರ್ಜ್ ಮಾಡುವಾಗ ಪರದೆಯು ಎಂದಿಗೂ ನಿದ್ರಾವಸ್ಥೆಗೆ ಹೋಗುವುದಿಲ್ಲ"</string>
     <string name="bt_hci_snoop_log" msgid="3340699311158865670">"ಬ್ಲೂಟೂತ್‌‌ HCI ಸ್ನೂಪ್‌ಲಾಗ್"</string>
-    <string name="bt_hci_snoop_log_summary" msgid="730247028210113851">"ಫೈಲ್‌ನಲ್ಲಿ ಎಲ್ಲ bluetooth HCI ಪ್ಯಾಕೆಟ್‌ಗಳನ್ನು ಸೆರೆಹಿಡಿಯಿರಿ"</string>
+    <string name="bt_hci_snoop_log_summary" msgid="730247028210113851">"ಫೈಲ್‌ನಲ್ಲಿ ಎಲ್ಲ ಬ್ಲೂಟೂತ್ HCI ಪ್ಯಾಕೆಟ್‌ಗಳನ್ನು ಸೆರೆಹಿಡಿಯಿರಿ"</string>
     <string name="oem_unlock_enable" msgid="6040763321967327691">"OEM ಅನ್‌ಲಾಕ್‌ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
     <string name="oem_unlock_enable_summary" msgid="4720281828891618376">"ಬೂಟ್‌ಲೋಡರ್‌ ಅನ್‌ಲಾಕ್‌ ಮಾಡಲು ಅನುಮತಿಸಿ"</string>
     <string name="confirm_enable_oem_unlock_title" msgid="4802157344812385674">"OEM ಅನ್‌ಲಾಕ್‌ ಮಾಡುವಿಕೆಯನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
@@ -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-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 03c0edf..2732853 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_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-lo-rLA/strings.xml b/packages/SettingsLib/res/values-lo-rLA/strings.xml
index 41a8eef..7b16fd9 100644
--- a/packages/SettingsLib/res/values-lo-rLA/strings.xml
+++ b/packages/SettingsLib/res/values-lo-rLA/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ປັບແຕ່ງເອງ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"ຊ່ວຍເຫຼືອ &amp; ຄຳຕິຊົມ"</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-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 6930c7a..85e044f 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tinkintas (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Pagalba ir atsiliepimai"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Meniu"</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-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 7734881..36378f2 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Pielāgots (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Palīdzība un atsauksmes"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Izvēlne"</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-ml-rIN/strings.xml b/packages/SettingsLib/res/values-ml-rIN/strings.xml
index 8bcbf79..09c07ea 100644
--- a/packages/SettingsLib/res/values-ml-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ml-rIN/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_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-mn-rMN/strings.xml b/packages/SettingsLib/res/values-mn-rMN/strings.xml
index 4fa3779..86a62a2 100644
--- a/packages/SettingsLib/res/values-mn-rMN/strings.xml
+++ b/packages/SettingsLib/res/values-mn-rMN/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_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-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-ms-rMY/strings.xml b/packages/SettingsLib/res/values-ms-rMY/strings.xml
index cf77254..8935581 100644
--- a/packages/SettingsLib/res/values-ms-rMY/strings.xml
+++ b/packages/SettingsLib/res/values-ms-rMY/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tersuai (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Bantuan &amp; maklum balas"</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-my-rMM/strings.xml b/packages/SettingsLib/res/values-my-rMM/strings.xml
index 9db8348..5f4dc50 100644
--- a/packages/SettingsLib/res/values-my-rMM/strings.xml
+++ b/packages/SettingsLib/res/values-my-rMM/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_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-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index cc4e567..76ff94f 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Egendefinert (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Hjelp og tilbakemelding"</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-ne-rNP/strings.xml b/packages/SettingsLib/res/values-ne-rNP/strings.xml
index a8a918b..8199cde 100644
--- a/packages/SettingsLib/res/values-ne-rNP/strings.xml
+++ b/packages/SettingsLib/res/values-ne-rNP/strings.xml
@@ -22,7 +22,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="1265540342578081461">"सञ्जालका लागि स्क्यान गर्न सक्दैन"</string>
     <string name="wifi_security_none" msgid="7985461072596594400">"कुनै पनि होइन"</string>
-    <string name="wifi_remembered" msgid="4955746899347821096">"बचत गरियो"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"सुरक्षित गरियो"</string>
     <string name="wifi_disabled_generic" msgid="4259794910584943386">"असक्षम पारियो"</string>
     <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP विन्यास असफल"</string>
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"वाईफाई जडान असफल"</string>
@@ -338,9 +338,8 @@
     <string name="screen_zoom_summary_large" msgid="4835294730065424084">"ठूलो"</string>
     <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"अझ ठूलो"</string>
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"सबैभन्दा ठूलो"</string>
-    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"अनुकूलन (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
+    <string name="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-pa-rIN/strings.xml b/packages/SettingsLib/res/values-pa-rIN/strings.xml
index f19ba3e..cb46376 100644
--- a/packages/SettingsLib/res/values-pa-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-pa-rIN/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_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-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-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 5d0b965..da2f76f 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizat (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Ajutor și feedback"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Meniu"</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-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index d301ce1..9600027 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_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-si-rLK/strings.xml b/packages/SettingsLib/res/values-si-rLK/strings.xml
index f21793b..b775db6 100644
--- a/packages/SettingsLib/res/values-si-rLK/strings.xml
+++ b/packages/SettingsLib/res/values-si-rLK/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_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-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index b478ecf..8130866 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Vlastné (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Pomocník a spätná väzba"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Ponuka"</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-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index b9da0eb..a3b666ca 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Po meri (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Pomoč in povratne informacije"</string>
     <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-sq-rAL/strings.xml b/packages/SettingsLib/res/values-sq-rAL/strings.xml
index c17376b..232ca0a 100644
--- a/packages/SettingsLib/res/values-sq-rAL/strings.xml
+++ b/packages/SettingsLib/res/values-sq-rAL/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"I personalizuar (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Ndihma dhe komentet"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Menyja"</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-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index f14cbdd..3c06d72 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Kiwango maalum (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Usaidizi na maoni"</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/res/values-ta-rIN/strings.xml b/packages/SettingsLib/res/values-ta-rIN/strings.xml
index 2640122..daf3ff2 100644
--- a/packages/SettingsLib/res/values-ta-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ta-rIN/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"தனிப்பயன் (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"உதவி &amp; கருத்து"</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-te-rIN/strings.xml b/packages/SettingsLib/res/values-te-rIN/strings.xml
index 60a4d72..31defb6 100644
--- a/packages/SettingsLib/res/values-te-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-te-rIN/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"అనుకూలం (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"సహాయం &amp; అభిప్రాయం"</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-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index fbb67bc..5ec5871 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_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-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 50c43bb..07e1c8bd 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Tulong at 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-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index c5ae71c..78b4a61 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Özel (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Yardım ve geri bildirim"</string>
     <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-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-ur-rPK/strings.xml b/packages/SettingsLib/res/values-ur-rPK/strings.xml
index 0b5e8a0..e1b545f 100644
--- a/packages/SettingsLib/res/values-ur-rPK/strings.xml
+++ b/packages/SettingsLib/res/values-ur-rPK/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_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/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 21e5b75..28dbe51 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tùy chỉnh (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Trợ giúp và phản hồi"</string>
     <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-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index ba657c6..7c8bb20 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_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-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 60f56f1..62c7715 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_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-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 6bb7308..17a62e1 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_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-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 6714b27..7e982ee 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Ngokwezifiso (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Usizo nempendulo"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Imenyu"</string>
-    <!-- no translation found for time_zone_gmt (2587097992671450782) -->
-    <skip />
+    <string name="time_zone_gmt" msgid="2587097992671450782">"I-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/drawer/Tile.java b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
index b16cd08..c7efb07 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
@@ -79,6 +79,11 @@
      */
     public Bundle metaData;
 
+    /**
+     * Optional key to use for this tile.
+     */
+    public String key;
+
     public Tile() {
         // Empty
     }
@@ -113,6 +118,7 @@
         dest.writeString(category);
         dest.writeInt(priority);
         dest.writeBundle(metaData);
+        dest.writeString(key);
     }
 
     public void readFromParcel(Parcel in) {
@@ -132,6 +138,7 @@
         category = in.readString();
         priority = in.readInt();
         metaData = in.readBundle();
+        key = in.readString();
     }
 
     Tile(Parcel in) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index 9442458..d12e8c0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -102,6 +102,12 @@
 
     /**
      * Name of the meta-data item that should be set in the AndroidManifest.xml
+     * to specify the key that should be used for the preference.
+     */
+    public static final String META_DATA_PREFERENCE_KEYHINT = "com.android.settings.keyhint";
+
+    /**
+     * Name of the meta-data item that should be set in the AndroidManifest.xml
      * to specify the icon that should be displayed for the preference.
      */
     public static final String META_DATA_PREFERENCE_ICON = "com.android.settings.icon";
@@ -292,6 +298,7 @@
             int icon = 0;
             CharSequence title = null;
             String summary = null;
+            String keyHint = null;
 
             // Get the activity's meta-data
             try {
@@ -317,6 +324,13 @@
                             summary = metaData.getString(META_DATA_PREFERENCE_SUMMARY);
                         }
                     }
+                    if (metaData.containsKey(META_DATA_PREFERENCE_KEYHINT)) {
+                        if (metaData.get(META_DATA_PREFERENCE_KEYHINT) instanceof Integer) {
+                            keyHint = res.getString(metaData.getInt(META_DATA_PREFERENCE_KEYHINT));
+                        } else {
+                            keyHint = metaData.getString(META_DATA_PREFERENCE_KEYHINT);
+                        }
+                    }
                 }
             } catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) {
                 if (DEBUG) Log.d(LOG_TAG, "Couldn't find info", e);
@@ -338,6 +352,8 @@
             // Replace the intent with this specific activity
             tile.intent = new Intent().setClassName(activityInfo.packageName,
                     activityInfo.name);
+            // Suggest a key for this tile
+            tile.key = keyHint;
 
             return true;
         }
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/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index 651a7cb..86b210a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -21,7 +21,9 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.util.ArrayMap;
@@ -43,6 +45,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.when;
 
@@ -54,11 +57,14 @@
     private Context mContext;
     @Mock
     private PackageManager mPackageManager;
+    @Mock
+    private Resources mResources;
 
     @Before
-    public void setUp() {
+    public void setUp() throws NameNotFoundException {
         MockitoAnnotations.initMocks(this);
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        when(mPackageManager.getResourcesForApplication(anyString())).thenReturn(mResources);
     }
 
     @Test
@@ -82,6 +88,27 @@
     }
 
     @Test
+    public void getTilesForIntent_shouldParseKeyHintForSystemApp() {
+        String keyHint = "key";
+        Intent intent = new Intent();
+        Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
+        List<Tile> outTiles = new ArrayList<>();
+        List<ResolveInfo> info = new ArrayList<>();
+        ResolveInfo resolveInfo = newInfo(true, null /* category */, keyHint);
+        info.add(resolveInfo);
+
+        when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
+                .thenReturn(info);
+
+        TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
+                null /* defaultCategory */, outTiles, false /* usePriority */,
+                false /* checkCategory */);
+
+        assertThat(outTiles.size()).isEqualTo(1);
+        assertThat(outTiles.get(0).key).isEqualTo(keyHint);
+    }
+
+    @Test
     public void getTilesForIntent_shouldSkipNonSystemApp() {
         final String testCategory = "category1";
         Intent intent = new Intent();
@@ -100,7 +127,12 @@
         assertThat(outTiles.isEmpty()).isTrue();
     }
 
+
     private ResolveInfo newInfo(boolean systemApp, String category) {
+        return newInfo(systemApp, category, null);
+    }
+
+    private ResolveInfo newInfo(boolean systemApp, String category, String keyHint) {
         ResolveInfo info = new ResolveInfo();
         info.system = systemApp;
         info.activityInfo = new ActivityInfo();
@@ -108,7 +140,13 @@
         info.activityInfo.name = "123";
         info.activityInfo.metaData = new Bundle();
         info.activityInfo.metaData.putString("com.android.settings.category", category);
+        if (keyHint != null) {
+            info.activityInfo.metaData.putString("com.android.settings.keyhint", keyHint);
+        }
         info.activityInfo.applicationInfo = new ApplicationInfo();
+        if (systemApp) {
+            info.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+        }
         return info;
     }
 }
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/notification_icon_area.xml b/packages/SystemUI/res/layout/notification_icon_area.xml
index c5b4e84..6732e6c 100644
--- a/packages/SystemUI/res/layout/notification_icon_area.xml
+++ b/packages/SystemUI/res/layout/notification_icon_area.xml
@@ -19,13 +19,7 @@
     android:id="@+id/notification_icon_area_inner"
     android:layout_width="match_parent"
     android:layout_height="match_parent" >
-    <com.android.systemui.statusbar.StatusBarIconView
-        android:id="@+id/moreIcon"
-        android:layout_width="@dimen/status_bar_icon_size"
-        android:layout_height="match_parent"
-        android:src="@drawable/stat_notify_more"
-        android:visibility="gone" />
-    <com.android.systemui.statusbar.phone.IconMerger
+    <com.android.systemui.statusbar.phone.NotificationIconContainer
         android:id="@+id/notificationIcons"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 63af3e0..6784254 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -42,7 +42,7 @@
     <LinearLayout android:id="@+id/status_bar_contents"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:paddingStart="6dp"
+        android:paddingStart="@dimen/status_bar_padding_start"
         android:paddingEnd="8dp"
         android:orientation="horizontal"
         >
diff --git a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
deleted file mode 100644
index 7df6bc6..0000000
--- a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<!--
-  ~ Copyright (C) 2014 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-
-<!-- Extends FrameLayout -->
-<com.android.systemui.statusbar.NotificationOverflowContainer
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="@dimen/notification_summary_height"
-    android:focusable="true"
-    android:clickable="true"
-    >
-
-    <com.android.systemui.statusbar.NotificationBackgroundView android:id="@+id/backgroundNormal"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        />
-    <com.android.systemui.statusbar.NotificationBackgroundView android:id="@+id/backgroundDimmed"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        />
-
-    <com.android.keyguard.AlphaOptimizedLinearLayout
-        android:id="@+id/content"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-        <TextView
-            android:id="@+id/more_text"
-            android:layout_width="32dp"
-            android:layout_height="32dp"
-            android:layout_marginStart="16dp"
-            android:layout_marginEnd="12dp"
-            android:layout_gravity="center_vertical"
-            android:background="@drawable/keyguard_overflow_number_background"
-            android:gravity="center"
-            android:textColor="#ff686868"
-            android:textStyle="bold"
-            android:textSize="14dp"
-            />
-        <com.android.systemui.statusbar.StatusBarIconView
-            android:id="@+id/more_icon_overflow"
-            android:layout_width="@dimen/status_bar_icon_size"
-            android:layout_height="match_parent"
-            android:src="@drawable/stat_notify_more"
-            android:tint="@color/keyguard_overflow_content_color"
-            android:visibility="gone"
-            />
-        <com.android.systemui.statusbar.NotificationOverflowIconsView
-            android:id="@+id/overflow_icons_view"
-            android:layout_gravity="center_vertical"
-            android:layout_marginEnd="8dp"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            />
-    </com.android.keyguard.AlphaOptimizedLinearLayout>
-
-    <com.android.systemui.statusbar.notification.FakeShadowView
-        android:id="@+id/fake_shadow"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
-</com.android.systemui.statusbar.NotificationOverflowContainer>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_shelf.xml b/packages/SystemUI/res/layout/status_bar_notification_shelf.xml
new file mode 100644
index 0000000..7bfbd3c
--- /dev/null
+++ b/packages/SystemUI/res/layout/status_bar_notification_shelf.xml
@@ -0,0 +1,47 @@
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<!-- Extends FrameLayout -->
+<com.android.systemui.statusbar.NotificationShelf
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/notification_shelf_height"
+    android:focusable="true"
+    android:clickable="true"
+    >
+
+    <com.android.systemui.statusbar.NotificationBackgroundView android:id="@+id/backgroundNormal"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        />
+    <com.android.systemui.statusbar.NotificationBackgroundView android:id="@+id/backgroundDimmed"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        />
+    <com.android.systemui.statusbar.phone.NotificationIconContainer
+        android:id="@+id/content"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:paddingStart="@dimen/shelf_icon_container_padding"
+        android:paddingEnd="@dimen/shelf_icon_container_padding"
+        android:gravity="center_vertical" />
+
+    <com.android.systemui.statusbar.notification.FakeShadowView
+        android:id="@+id/fake_shadow"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+</com.android.systemui.statusbar.NotificationShelf>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 5294c9c..a511c58 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Minder dringende kennisgewings hieronder"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Tik weer om oop te maak"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Sleep op om te ontsluit"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Hierdie toestel word bestuur"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Hierdie toestel word deur <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> bestuur"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Swiep vanaf ikoon vir foon"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Swiep vanaf ikoon vir stembystand"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Swiep vanaf ikoon vir kamera"</string>
@@ -451,6 +453,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..b40bd90 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"በጣም አስቸካይ ያልሆኑ ማሳወቂያዎች ከታች"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"ለመክፈት ዳግም መታ ያድርጉ"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"ለማስከፈት ወደ ላይ ያንሸራትቱ"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"ይህ መሣሪያ የሚተዳደር ነው"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"ይህ መሣሪያ በ<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> የሚተዳደር ነው"</string>
     <string name="phone_hint" msgid="4872890986869209950">"ለስልክ ከአዶ ላይ ጠረግ ያድርጉ"</string>
     <string name="voice_hint" msgid="8939888732119726665">"ለድምጽ ረዳት ከአዶ ጠረግ ያድርጉ"</string>
     <string name="camera_hint" msgid="7939688436797157483">"ለካሜራ ከአዶ ላይ ጠረግ ያድርጉ"</string>
@@ -451,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-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index a1a8f8d..9ec84f9 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -358,6 +358,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"الإشعارات الأقل إلحاحًا أدناه"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"انقر مرة أخرى للفتح"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"مرر سريعًا لأعلى لإلغاء القفل"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"تتم إدارة هذا الجهاز"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"تتم إدارة هذا الجهاز بواسطة <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"يمكنك التمرير سريعًا من الرمز لتشغيل الهاتف"</string>
     <string name="voice_hint" msgid="8939888732119726665">"يمكنك التمرير سريعًا من الرمز لتشغيل المساعد الصوتي"</string>
     <string name="camera_hint" msgid="7939688436797157483">"يمكنك التمرير سريعًا من الرمز لتشغيل الكاميرا"</string>
@@ -459,6 +461,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..14537a1 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Daha az təcili bildirişlər aşağıdadır"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Açmaq üçün yenidən tıklayın"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Kiliddən çıxarmaq üçün yuxarı çəkin"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Bu cihaz idarə olunur"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Bu cihaz <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> tərəfindən idarə olunur"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Telefon üçün ikonadan sürüşdürün"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Səs yardımçısı üçün ikonadan sürüşdürün"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Kamera üçün ikonadan sürüşdürün"</string>
@@ -451,6 +453,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..c92490f 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -352,6 +352,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Manje hitna obaveštenja su u nastavku"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Dodirnite ponovo da biste otvorili"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Prevucite nagore da biste otključali"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Ovim uređajem se upravlja"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Ovim uređajem upravlja <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Prevucite od ikone za telefon"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Prevucite od ikone za glasovnu pomoć"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Prevucite od ikone za kameru"</string>
@@ -453,6 +455,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..6ae9db5 100644
--- a/packages/SystemUI/res/values-be-rBY/strings.xml
+++ b/packages/SystemUI/res/values-be-rBY/strings.xml
@@ -356,6 +356,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Менш тэрміновыя апавяшчэнні ніжэй"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Дакраніцеся яшчэ раз, каб адкрыць"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Правядзіце пальцам уверх, каб разблакіраваць"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Гэта прылада знаходзіцца пад кіраваннем"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Гэта прылада знаходзіцца пад кіраваннем <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Тэлефон: правядзіце пальцам ад значка"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Галасавая дапамога: правядзіце пальцам ад значка"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Камера: правядзіце пальцам ад значка"</string>
@@ -457,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-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index bf3a614..6079354 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Ппоказване на по-малко спешните известия по-долу"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Докоснете отново, за да отворите"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Плъзнете нагоре, за да отключите"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Това устройство се управлява"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Това устройство се управлява от <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Плъзнете с пръст от иконата, за да използвате телефона"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Прекарайте пръст от иконата, за да получите гласова помощ"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Плъзнете с пръст от иконата, за да включите камерата"</string>
@@ -451,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-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index bd599bc..32d00f6 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"নিচে অপেক্ষাকৃত কম জরুরী বিজ্ঞপ্তিগুলি"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"খোলার জন্য আবার আলতো চাপুন"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"আনলক করতে উপরের দিকে সোয়াইপ করুন"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"এই ডিভাইসটি পরিচালিত"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"এই ডিভাইসটি <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> এর দ্বারা পরিচালিত"</string>
     <string name="phone_hint" msgid="4872890986869209950">"ফোনের জন্য আইকন থেকে সোয়াইপ করুন"</string>
     <string name="voice_hint" msgid="8939888732119726665">"ভয়েস সহায়তার জন্য আইকন থেকে সোয়াইপ করুন"</string>
     <string name="camera_hint" msgid="7939688436797157483">"ক্যামেরার জন্য আইকন থেকে সোয়াইপ করুন"</string>
@@ -451,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-bs-rBA/strings.xml b/packages/SystemUI/res/values-bs-rBA/strings.xml
index 5ba720c..0c35e18 100644
--- a/packages/SystemUI/res/values-bs-rBA/strings.xml
+++ b/packages/SystemUI/res/values-bs-rBA/strings.xml
@@ -352,6 +352,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Prikaži manje važna obavještenja ispod"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Dodirnite ponovo da otvorite"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Prevucite prema gore da otključate"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Ovim uređajem upravlja"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Ovim uređajem upravlja <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Prevucite preko ikone da otvorite telefon"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Prevucite preko ikone za glasovnu pomoć"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Prevucite od ikone da otvorite kameru"</string>
@@ -453,6 +455,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..fd660ac 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Notificacions menys urgents a continuació"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Torna a tocar per obrir-la."</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Llisca cap amunt per desbloquejar el teclat"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Aquest és un dispositiu gestionat"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> gestiona aquest dispositiu"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Llisca des de la icona per obrir el telèfon"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Llisca des de la icona per obrir l\'assistent de veu"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Llisca des de la icona per obrir la càmera"</string>
@@ -451,6 +453,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 +475,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..a045ecd 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -356,6 +356,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Méně urgentní oznámení níže"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Oznámení otevřete opětovným klepnutím"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Zařízení odemknete přejetím prstem nahoru"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Toto zařízení je spravováno"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Toto zařízení je spravováno organizací <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Telefon otevřete přejetím prstem od ikony"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Hlasovou asistenci otevřete přejetím prstem od ikony"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Fotoaparát otevřete přejetím prstem od ikony"</string>
@@ -457,6 +459,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..3eeabaa 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Mindre presserende underretninger nedenfor"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Tryk igen for at åbne"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Stryg opad for at låse op"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Dette er en administreret enhed"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Denne enhed administreres af <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Stryg fra telefonikonet"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Stryg fra mikrofonikonet"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Stryg fra kameraikonet"</string>
@@ -451,6 +453,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Hjælpefunktioner"</item>
   </string-array>
     <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>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index b3a457d..603be91 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -352,6 +352,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Weniger dringende Benachrichtigungen unten"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Erneut tippen, um Benachrichtigung zu öffnen"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Zum Entsperren nach oben wischen"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Dieses Gerät wird verwaltet"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Dieses Gerät wird von <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> verwaltet"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Zum Öffnen des Telefons vom Symbol wegwischen"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Zum Öffnen des Sprachassistenten vom Symbol wegwischen"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Zum Öffnen der Kamera vom Symbol wegwischen"</string>
@@ -453,6 +455,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Bedienungshilfen"</item>
   </string-array>
     <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>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 050d7f8..2b160c7 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Λιγότερο επείγουσες ειδοποιήσεις παρακάτω"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Πατήστε ξανά για να ανοίξετε"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Σύρετε για να ξεκλειδώσετε"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Αυτή η συσκευή είναι διαχειριζόμενη"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Τη συσκευή διαχειρίζεται ο οργανισμός <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Σύρετε προς τα έξω για τηλέφωνο"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Σύρετε προς τα έξω για voice assist"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Σύρετε προς τα έξω για κάμερα"</string>
@@ -451,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-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 9aca3cc..d73e130 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Less urgent notifications below"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Tap again to open"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Swipe up to unlock"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"This device is managed"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"This device is managed by <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Swipe from icon for phone"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Swipe from icon for voice assist"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Swipe from icon for camera"</string>
@@ -451,6 +453,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..d73e130 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Less urgent notifications below"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Tap again to open"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Swipe up to unlock"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"This device is managed"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"This device is managed by <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Swipe from icon for phone"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Swipe from icon for voice assist"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Swipe from icon for camera"</string>
@@ -451,6 +453,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..d73e130 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Less urgent notifications below"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Tap again to open"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Swipe up to unlock"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"This device is managed"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"This device is managed by <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Swipe from icon for phone"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Swipe from icon for voice assist"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Swipe from icon for camera"</string>
@@ -451,6 +453,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..6f2c7d5 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -352,6 +352,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Notificaciones menos urgentes abajo"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Presionar de nuevo para abrir"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Desliza el dedo hacia arriba para desbloquear el teléfono"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Este dispositivo está administrado"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> administra este dispositivo"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Desliza el dedo para desbloquear el teléfono."</string>
     <string name="voice_hint" msgid="8939888732119726665">"Desliza el dedo desde el ícono para abrir asistente de voz."</string>
     <string name="camera_hint" msgid="7939688436797157483">"Desliza el dedo para acceder a la cámara."</string>
@@ -453,6 +455,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..ba9154d 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -352,6 +352,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Notificaciones menos urgente abajo"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Toca de nuevo para abrir"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Desliza el dedo hacia arriba para desbloquear"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Este es un dispositivo administrado"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Este dispositivo está administrado por <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Desliza desde el icono para abrir el teléfono"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Desliza desde el icono para abrir asistente de voz"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Desliza desde el icono para abrir la cámara"</string>
@@ -453,6 +455,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 +494,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..7566137 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -352,6 +352,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Vähem kiireloomulised märguanded on allpool"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Avamiseks puudutage uuesti"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Lukustuse tühistamiseks pühkige üles"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Seda seadet hallatakse"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Seda seadet haldab <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Telefoni kasutamiseks pühkige ikoonilt eemale"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Häälabi kasutamiseks pühkige ikoonilt eemale"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Kaamera kasutamiseks pühkige ikoonilt eemale"</string>
@@ -453,6 +455,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Juurdepääsetavus"</item>
   </string-array>
     <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>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index d6578a2..b78ca62 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -352,6 +352,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Horren premiazkoak ez diren jakinarazpenak daude behean"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Irekitzeko, ukitu berriro"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Desblokeatzeko, pasatu hatza gorantz"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Gailu kudeatu bat da hau"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> erakundeak kudeatzen du gailu hau"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Pasatu hatza ikonotik, telefonoa irekitzeko"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Pasatu hatza ikonotik, ahots-laguntza irekitzeko"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Pasatu hatza ikonotik, kamera irekitzeko"</string>
@@ -453,6 +455,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..de596d2 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"اعلان‌های کمتر فوری در زیر"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"دوباره ضربه بزنید تا باز شود"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"برای باز کردن قفل سریع به بالا بکشید"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"این دستگاه مدیریت می‌شود"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"این دستگاه توسط <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> مدیریت می‌شود"</string>
     <string name="phone_hint" msgid="4872890986869209950">"انگشتتان را از نماد تلفن تند بکشید"</string>
     <string name="voice_hint" msgid="8939888732119726665">"برای «دستیار صوتی»، تند بکشید"</string>
     <string name="camera_hint" msgid="7939688436797157483">"انگشتتان را از نماد دوربین تند بکشید"</string>
@@ -451,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-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 08572fe..234a850 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Vähemmän kiireelliset ilmoitukset ovat alla"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Avaa napauttamalla uudelleen"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Avaa lukitus pyyhkäisemällä ylös"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Tämä on hallinnoitu laite."</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Tätä laitetta hallinnoi <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>."</string>
     <string name="phone_hint" msgid="4872890986869209950">"Avaa puhelu pyyhkäisemällä."</string>
     <string name="voice_hint" msgid="8939888732119726665">"Avaa ääniapuri pyyhkäisemällä kuvakkeesta."</string>
     <string name="camera_hint" msgid="7939688436797157483">"Avaa kamera pyyhkäisemällä."</string>
@@ -451,6 +453,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..11edeb9 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -352,6 +352,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Notifications moins urgentes affichées ci-dessous"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Touchez à nouveau pour ouvrir"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Glissez vers le haut pour déverrouiller"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Cet appareil est géré"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Cet appareil est géré par <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Balayez à partir de l\'icône pour accéder au téléphone"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Balayez à partir de l\'icône pour accéder à l\'assist. vocale"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Balayez à partir de l\'icône pour accéder à l\'appareil photo"</string>
@@ -453,6 +455,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. 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>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 3b138c2..fa9494e 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -352,6 +352,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Notifications moins urgentes ci-dessous"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Appuyer à nouveau pour ouvrir"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Faire glisser pour déverrouiller"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Cet appareil est géré"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Cet appareil est géré par <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Balayer pour téléphoner"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Balayer l\'écran depuis l\'icône pour l\'assistance vocale"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Balayer pour prendre une photo"</string>
@@ -453,6 +455,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. 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>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 579335d..2f9b2e6 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -352,6 +352,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Notificacións menos urxentes abaixo"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Toca de novo para abrir"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Pasa o dedo cara arriba para desbloquear"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Este dispositivo está xestionado"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Este dispositivo está xestionado por <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Pasa o dedo desde a icona para acceder ao teléfono"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Pasa o dedo desde a icona para acceder ao asistente de voz"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Pasa o dedo desde a icona para acceder á cámara"</string>
@@ -453,6 +455,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..3649e85 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"નીચે ઓછી તાકીદની સૂચનાઓ"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"ખોલવા માટે ફરીથી ટૅપ કરો"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"અનલૉક કરવા માટે ઉપર સ્વાઇપ કરો"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"આ ઉપકરણ સંચાલિત છે"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"આ ઉપકરણ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> દ્વારા સંચાલિત થાય છે"</string>
     <string name="phone_hint" msgid="4872890986869209950">"ફોન માટે આયકનમાંથી સ્વાઇપ કરો"</string>
     <string name="voice_hint" msgid="8939888732119726665">"વૉઇસ સહાય માટે આયકનમાંથી સ્વાઇપ કરો"</string>
     <string name="camera_hint" msgid="7939688436797157483">"કૅમેરા માટે આયકનમાંથી સ્વાઇપ કરો"</string>
@@ -451,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-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 97f3926..7fd5eb6 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"कम अत्यावश्यक सूचनाएं नीचे दी गई हैं"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"खोलने के लिए पुन: टैप करें"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"अनलॉक करने के लिए ऊपर स्वाइप करें"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"यह डिवाइस प्रबंधित है"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"इस डिवाइस के प्रबंधक <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> हैं"</string>
     <string name="phone_hint" msgid="4872890986869209950">"फ़ोन के लिए आइकन से स्वाइप करें"</string>
     <string name="voice_hint" msgid="8939888732119726665">"वॉइस सहायक के लिए आइकन से स्वाइप करें"</string>
     <string name="camera_hint" msgid="7939688436797157483">"कैमरे के लिए आइकन से स्वाइप करें"</string>
@@ -451,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-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 7ff63bd..c105c23 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -352,6 +352,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Manje hitne obavijesti pri dnu"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Dodirnite opet za otvaranje"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Prijeđite prstom prema gore za otključavanje"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Ovim se uređajem upravlja"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Ovim uređajem upravlja <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Prijeđite prstom od ikone za telefon"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Prijeđite prstom od ikone za glasovnu pomoć"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Prijeđite prstom od ikone za fotoaparat"</string>
@@ -453,6 +455,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..9944b21 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"A kevésbé sürgős értesítések lentebb vannak"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Koppintson rá ismét a megnyitáshoz"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Húzza felfelé az ujját a feloldáshoz"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Ez az eszköz felügyelt"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Az eszközt a(z) <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> felügyeli."</string>
     <string name="phone_hint" msgid="4872890986869209950">"A telefonhoz csúsztasson az ikonról"</string>
     <string name="voice_hint" msgid="8939888732119726665">"A hangsegéd eléréséhez csúsztassa ujját az ikonról"</string>
     <string name="camera_hint" msgid="7939688436797157483">"A fényképezőhöz csúsztasson az ikonról"</string>
@@ -451,6 +453,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..1c3e9b3 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Պակաս հրատապ ծանուցումները ստորև"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Կրկին հպեք՝ բացելու համար"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Սահեցրեք վերև` ապակողպելու համար"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Այս սարքը կառավարվում է"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Այս սարքը կառավարվում է <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>-ի կողմից"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Սահահարվածեք հեռախոսի պատկերակից"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Սահահարվածեք ձայնային հուշման պատկերակից"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Սահահարվածեք խցիկի պատկերակից"</string>
@@ -451,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-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 6444ae5..e1e522e 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Notifikasi kurang darurat di bawah"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Ketuk lagi untuk membuka"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Gesek ke atas untuk membuka kunci"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Perangkat ini dikelola"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Perangkat ini dikelola oleh <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Gesek dari ikon untuk telepon"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Gesek dari ikon untuk mengaktifkan bantuan suara"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Gesek dari ikon untuk kamera"</string>
@@ -451,6 +453,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..d92092d 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Minna áríðandi tilkynningar fyrir neðan"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Ýttu aftur til að opna"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Strjúktu upp til að opna"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Þessu tæki er stýrt"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Þessu tæki er stýrt af <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Strjúktu frá tákninu fyrir síma"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Strjúktu frá tákninu fyrir raddaðstoð"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Strjúktu frá tákninu fyrir myndavél"</string>
@@ -451,6 +453,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..43b5f34 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -352,6 +352,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Notifiche meno urgenti in basso"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Tocca ancora per aprire"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Scorri verso l\'alto per sbloccare"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Questo dispositivo è gestito"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Questo dispositivo è gestito da <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Scorri per accedere al telefono"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Scorri dall\'icona per accedere a Voice Assist"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Scorri dall\'icona per accedere alla fotocamera"</string>
@@ -453,6 +455,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..b51020b 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -354,6 +354,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"הודעות בדחיפות נמוכה יותר בהמשך"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"הקש שוב כדי לפתוח"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"החלק מעלה כדי לבטל את הנעילה"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"המכשיר הזה מנוהל"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"המכשיר הזה מנוהל על ידי <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"החלק מהסמל כדי להפעיל את הטלפון"</string>
     <string name="voice_hint" msgid="8939888732119726665">"החלק מהסמל כדי להפעיל את המסייע הקולי"</string>
     <string name="camera_hint" msgid="7939688436797157483">"החלק מהסמל כדי להפעיל את המצלמה"</string>
@@ -455,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-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 6ef9f73..a949cbf 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -352,6 +352,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"緊急度の低い通知を下に表示"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"開くにはもう一度タップしてください"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"ロック解除するには上にスワイプしてください"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"この端末は組織が管理しています"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"この端末は <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> が管理しています"</string>
     <string name="phone_hint" msgid="4872890986869209950">"右にスワイプして通話"</string>
     <string name="voice_hint" msgid="8939888732119726665">"アイコンからスワイプして音声アシストを起動"</string>
     <string name="camera_hint" msgid="7939688436797157483">"左にスワイプしてカメラを起動"</string>
@@ -453,6 +455,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-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 695279d..41de915 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"ქვემოთ მითითებულია ნაკლებად სასწრაფო შეტყობინებები"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"შეეხეთ ისევ გასახსნელად"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"გაასრიალეთ ზევით განსაბლოკად"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"ეს მოწყობილობა მართულია"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"ამ მოწყობილობას მართავს <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"ტელეფონისთვის გადაფურცლეთ ხატულადან"</string>
     <string name="voice_hint" msgid="8939888732119726665">"ხმოვანი დახმარებისთვის გადაფურცლეთ ხატულადან"</string>
     <string name="camera_hint" msgid="7939688436797157483">"კამერისთვის გადაფურცლეთ ხატულადან"</string>
@@ -451,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-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index ba71182..0f9699a 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Шұғылдығы азырақ хабарландырулар төменде"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Ашу үшін қайта түртіңіз"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Құлыпты ашу үшін жоғары сырғытыңыз"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Бұл құрылғыны ұйым басқарады"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Бұл құрылғыны <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> басқарады"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Телефонды ашу үшін белгішеден әрі қарай сырғытыңыз"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Дауыс көмекшісін ашу үшін белгішеден әрі қарай сырғытыңыз"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Камераны ашу үшін белгішеден әрі қарай сырғытыңыз"</string>
@@ -451,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-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index b222555..4ad9ac8 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"ការ​ជូន​ដំណឹង​​មិន​សូវ​បន្ទាន់​ខាង​ក្រោម"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"ប៉ះ​ម្ដង​ទៀត ដើម្បី​បើក"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"អូស​ឡើង​លើ ដើម្បី​ដោះ​សោ"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"ឧបករណ៍នេះស្ថិតក្រោមការគ្រប់គ្រង"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"ឧបករណ៍នេះត្រូវបានគ្រប់គ្រងដោយ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"អូសចេញពីរូបតំណាងដើម្បីប្រើទូរស័ព្ទ"</string>
     <string name="voice_hint" msgid="8939888732119726665">"អូសចេញពីរូបតំណាងដើម្បីប្រើជំនួយសំឡេង"</string>
     <string name="camera_hint" msgid="7939688436797157483">"អូសចេញពីរូបតំណាងដើម្បីប្រើកាមេរ៉ា"</string>
@@ -451,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-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index b2a6f27..3a29a6f 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"ಕೆಳಗೆ ಕಡಿಮೆ ಅವಸರದ ಅಧಿಸೂಚನೆಗಳು"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"ತೆರೆಯಲು ಮತ್ತೆ ಟ್ಯಾಪ್‌ ಮಾಡಿ"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"ಅನ್‌ಲಾಕ್‌ ಮಾಡಲು ಸ್ವೈಪ್‌ ಮಾಡಿ"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"ಈ ಸಾಧನವನ್ನು ನಿರ್ವಹಿಸಲಾಗಿದೆ"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"ಈ ಸಾಧನವನ್ನು <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ರಿಂದ ನಿರ್ವಹಿಸಲಾಗಿದೆ"</string>
     <string name="phone_hint" msgid="4872890986869209950">"ಫೋನ್‌ಗಾಗಿ ಐಕಾನ್‌ನಿಂದ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
     <string name="voice_hint" msgid="8939888732119726665">"ಧ್ವನಿ ಸಹಾಯಕ್ಕಾಗಿ ಐಕಾನ್‌ನಿಂದ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
     <string name="camera_hint" msgid="7939688436797157483">"ಕ್ಯಾಮರಾಗಾಗಿ ಐಕಾನ್‌ನಿಂದ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
@@ -451,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-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index cefb57a..cff469c 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -352,6 +352,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"아래에 덜 급한 알림 표시"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"다시 탭하여 열기"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"위로 스와이프하여 잠금 해제"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"관리되는 기기입니다."</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>에서 관리하는 기기입니다."</string>
     <string name="phone_hint" msgid="4872890986869209950">"전화 기능을 사용하려면 아이콘에서 스와이프하세요."</string>
     <string name="voice_hint" msgid="8939888732119726665">"음성 지원을 사용하려면 아이콘에서 스와이프하세요."</string>
     <string name="camera_hint" msgid="7939688436797157483">"카메라를 사용하려면 아이콘에서 스와이프하세요."</string>
@@ -453,6 +455,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-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index e013c6b..a0675c0 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Анчейин шашылыш эмес эскертмелер төмөндө"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Ачуу үчүн кайра таптап коюңуз"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Кулпуну ачуу үчүн серпип коюңуз"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Башкарылган түзмөк"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Бул түзмөк <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> тарабынан башкарылат"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Сүрөтчөнү серпип телефонго өтүңүз"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Сүрөтчөнү серпип үн жардамчысына өтүңүз"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Сүрөтчөнү серпип камерага өтүңүз"</string>
@@ -451,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-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 94e789a..2056194 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"ການ​ແຈ້ງເຕືອນ​ທີ່​ສຳຄັນ​ໜ້ອຍ​ກວ່າ​ຢູ່​ດ້ານ​ລຸ່ມ"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"ແຕະ​ອີກ​ຄັ້ງ​ເພື່ອ​ເປີດ"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"ເລື່ອນ​ຂຶ້ນ​ເພື່ອ​ປົດ​ລັອກ"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"ອຸປະກອນນີ້ຖືກຈັດການຢູ່"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"ອຸປະກອນນີ້ຖືກຈັດການໂດຍ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"ປັດ​ຈາກ​ໄອ​ຄອນ​ສຳ​ລັບ​ໂທ​ລະ​ສັບ"</string>
     <string name="voice_hint" msgid="8939888732119726665">"ປັດ​ຈາກ​ໄອ​ຄອນ​ສຳ​ລັບ​ການ​ຊ່ວຍ​ທາງ​ສຽງ"</string>
     <string name="camera_hint" msgid="7939688436797157483">"ປັດ​ຈາກ​ໄອ​ຄອນ​ສຳ​ລັບ​ກ້ອງ​ຖ່າຍ​ຮູບ"</string>
@@ -451,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-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 5af5979..6dfdbe6 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -354,6 +354,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Mažiau skubūs pranešimai toliau"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Palieskite dar kartą, kad atidarytumėte"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Perbraukite aukštyn, kad atrakintumėte"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Šis įrenginys tvarkomas"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Šį įrenginį tvarko <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Perbraukite iš telefono piktogramos"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Perbraukite iš „Voice Assist“ piktogramos"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Perbraukite iš fotoaparato piktogramos"</string>
@@ -455,6 +457,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Pritaikymas neįgaliesiems"</item>
   </string-array>
     <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>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 503c8c8..3862a8e 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -352,6 +352,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Mazāk steidzami paziņojumi tiek rādīti tālāk"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Pieskarieties vēlreiz, lai atvērtu"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Velciet uz augšu, lai atbloķētu"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Šī ierīce tiek pārvaldīta"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Šo ierīci pārvalda <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Lai lietotu tālruni, velciet no ikonas"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Lai lietotu balss palīgu, velciet no ikonas"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Lai lietotu kameru, velciet no ikonas"</string>
@@ -453,6 +455,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Pieejamība"</item>
   </string-array>
     <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>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 62fc350..5d28e2b 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Долу се помалку итни известувања"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Допрете повторно за да се отвори"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Повлечете за да се отклучи"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Со уредов се управува"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Уредов го управува <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Повлечете од иконата за телефонот"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Повлечете од иконата за гласовна помош"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Повлечете од иконата за камерата"</string>
@@ -451,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>
@@ -525,7 +528,7 @@
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Штедач на батерија"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Ја намалува изведбата и податоците во заднина"</string>
     <string name="keyboard_key_button_template" msgid="6230056639734377300">"Копче <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <string name="keyboard_key_home" msgid="2243500072071305073">"Почетна страница"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home-копче"</string>
     <string name="keyboard_key_back" msgid="2337450286042721351">"Назад"</string>
     <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Стрелка нагоре"</string>
     <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Стрелка надолу"</string>
@@ -545,7 +548,7 @@
     <string name="keyboard_key_page_up" msgid="5654098530106845603">"Страница нагоре"</string>
     <string name="keyboard_key_page_down" msgid="8720502083731906136">"Страница надолу"</string>
     <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Избриши"</string>
-    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Почетна страница"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home-копче"</string>
     <string name="keyboard_key_move_end" msgid="5901174332047975247">"Крај"</string>
     <string name="keyboard_key_insert" msgid="8530501581636082614">"Вметни"</string>
     <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 9e7d2f2..f24b1e6 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"ആവശ്യം കുറഞ്ഞ അറിയിപ്പുകൾ ചുവടെ നൽകിയിരിക്കുന്നു"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"തുറക്കുന്നതിന് വീണ്ടും ടാപ്പുചെയ്യുക"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"അൺലോക്കുചെയ്യുന്നതിന് മുകളിലേക്ക് സ്വൈപ്പുചെയ്യുക"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"മാനേജുചെയ്യപ്പെടുന്ന ഉപകരണമാണിത്"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> മാനേജുചെയ്യുന്ന ഉപകരണമാണിത്"</string>
     <string name="phone_hint" msgid="4872890986869209950">"ഫോൺ ഐക്കണിൽ നിന്ന് സ്വൈപ്പുചെയ്യുക"</string>
     <string name="voice_hint" msgid="8939888732119726665">"വോയ്‌സ് അസിസ്റ്റിനായുള്ള ഐക്കണിൽ നിന്ന് സ്വൈപ്പുചെയ്യുക"</string>
     <string name="camera_hint" msgid="7939688436797157483">"ക്യാമറ ഐക്കണിൽ നിന്ന് സ്വൈപ്പുചെയ്യുക"</string>
@@ -451,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-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 04fb4c2..e285a42 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -348,6 +348,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Яаралтай биш мэдэгдлүүдийг доор"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Нээхийн тулд дахин товшино уу"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Түгжээг тайлах бол шудрана уу"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Энэ төхөөрөмжийг удирдаж байна"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Энэ төхөөрөмжийг <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> удирддаг"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Утсыг гаргахын тулд дүрс тэмдгээс шудрах"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Дуут туслахыг нээхийн тулд дүрс тэмдгээс шудрах"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Камер нээхийн тулд дүрс тэмдгийг шудрах"</string>
@@ -410,12 +412,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>
@@ -449,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-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index a21019a..f94e859 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"खाली कमी तातडीच्या सूचना"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"उघडण्यासाठी पुन्हा टॅप करा"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"अनलॉक करण्यासाठी स्वाइप करा"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"हे डिव्हाइस व्यवस्थापित केले आहे"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"हे डिव्हाइस <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ने व्यवस्थापित केले आहे"</string>
     <string name="phone_hint" msgid="4872890986869209950">"फोनसाठी चिन्हावरून स्वाइप करा"</string>
     <string name="voice_hint" msgid="8939888732119726665">"व्हॉइस सहाय्यासाठी चिन्हावरून स्वाइप करा"</string>
     <string name="camera_hint" msgid="7939688436797157483">"कॅमेर्‍यासाठी चिन्हावरून स्वाइप करा"</string>
@@ -451,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-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index ce94295..0c5924d 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Pemberitahuan kurang penting di bawah"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Ketik lagi untuk membuka"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Leret ke atas untuk membuka kunci"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Peranti ini terurus"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Peranti ini diurus oleh <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Leret dari ikon untuk telefon"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Leret dari ikon untuk bantuan suara"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Leret dari ikon untuk kamera"</string>
@@ -451,6 +453,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Kebolehaksesan"</item>
   </string-array>
     <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>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 8ab1de0..af68511 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"အရေးပါမှု နည်းသည့် အကြောင်းကြားချက်များ အောက်မှာ"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"ဖွင့်ရန် ထပ်ပြီး ပုတ်ပါ"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"သော့ဖွင့်ရန် အပေါ်သို့ ပွတ်ဆွဲပါ"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"ဤစက်ပစ္စည်းကို စီမံခန့်ခွဲထားပါသည်"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"ဤစက်ပစ္စည်းကို <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> က စီမံခန့်ခွဲထားပါသည်"</string>
     <string name="phone_hint" msgid="4872890986869209950">"ဖုန်းအတွက် သင်္ကေတပုံအား ပွတ်ဆွဲပါ"</string>
     <string name="voice_hint" msgid="8939888732119726665">"အသံအကူအညီအတွက် သင်္ကေတပုံအား ပွတ်ဆွဲပါ"</string>
     <string name="camera_hint" msgid="7939688436797157483">"ကင်မရာအတွက် သင်္ကေတပုံအား ပွတ်ဆွဲပါ"</string>
@@ -451,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-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index c6312e1..1b9c35a 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Mindre presserende varsler nedenfor"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Trykk på nytt for å åpne"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Sveip oppover for å låse opp"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Denne enheten blir administrert"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Denne enheten administreres av <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Sveip ikonet for å åpne telefon"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Sveip fra ikonet for å åpne talehjelp"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Sveip ikonet for å åpne kamera"</string>
@@ -451,6 +453,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..1d33a7d 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -331,7 +331,7 @@
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"विभाजित स्क्रिनको प्रयोग गर्नका लागि यहाँ तान्नुहोस्"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"तेर्सो रूपमा विभाजन गर्नुहोस्"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ठाडो रूपमा विभाजन गर्नुहोस्"</string>
-    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"अनुकूलन विभाजन गर्नुहोस्"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"आफू अनुकूल विभाजन गर्नुहोस्"</string>
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"चार्ज भयो"</string>
@@ -343,13 +343,15 @@
     <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>को लागि माथि धिसार्नुहोस्"</string>
     <string name="description_direction_left" msgid="7207478719805562165">"स्लाइड <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>को लागि बायाँ।"</string>
     <string name="zen_priority_introduction" msgid="3070506961866919502">"अलार्म, रिमाइन्डर, घटना, र तपाईँले निर्दिष्ट गर्नुहुने कलरहरू देखि बाहेक, आवाज र कम्पनले तपाईँ लाई वाधा गर्ने छैन।"</string>
-    <string name="zen_priority_customize_button" msgid="7948043278226955063">"अनुकूलन गर्नुहोस्"</string>
+    <string name="zen_priority_customize_button" msgid="7948043278226955063">"आफू अनुकूल बनाउनुहोस्"</string>
     <string name="zen_silence_introduction_voice" msgid="2284540992298200729">"यसले अलार्म, संगीत, भिडियो, र खेलहरू लगायतका सबै ध्वनि र कम्पन रोक्छ। तपाईँ अझै पनि फोन कल गर्न सक्षम हुनुहुन्छ।"</string>
     <string name="zen_silence_introduction" msgid="3137882381093271568">"यसले अलार्म, संगीत, भिडियोहरू र खेलहरूसहित सबै ध्वनिहरू र कम्पनहरूलाई रोक्छ।"</string>
     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
     <string name="speed_bump_explanation" msgid="1288875699658819755">"तल कम जरुरी सूचनाहरू"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"खोल्न पुनः ट्याप गर्नुहोस्"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"अनलक गर्न स्वाप गर्नुहोस्"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"यो यन्त्र व्यवस्थापन गरिएको छ"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"यो यन्त्र <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> द्वारा व्यवस्थापन गरिएको छ"</string>
     <string name="phone_hint" msgid="4872890986869209950">"फोनको लागि आइकनबाट स्वाइप गर्नुहोस्"</string>
     <string name="voice_hint" msgid="8939888732119726665">"आवाज सहायताका लागि आइकनबाट स्वाइप गर्नुहोस्"</string>
     <string name="camera_hint" msgid="7939688436797157483">"क्यामेराको लागि आइकनबाट स्वाइप गर्नुहोस्"</string>
@@ -451,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>
@@ -480,7 +483,7 @@
     <string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"Hotspot"</string>
     <string name="accessibility_managed_profile" msgid="6613641363112584120">"कार्य प्रोफाइल"</string>
     <string name="tuner_warning_title" msgid="7094689930793031682">"केहीका लागि रमाइलो हुन्छ तर सबैका लागि होइन"</string>
-    <string name="tuner_warning" msgid="8730648121973575701">"प्रणाली UI ट्युनरले तपाईँलाई Android प्रयोगकर्ता इन्टरफेस अनुकूलन गर्न र ट्विक गर्न थप तरिकाहरू प्रदान गर्छ। यी प्रयोगात्मक सुविधाहरू भावी विमोचनमा परिवर्तन हुन, बिग्रिन वा हराउन सक्ने छन्। सावधानीपूर्वक अगाडि बढ्नुहोस्।"</string>
+    <string name="tuner_warning" msgid="8730648121973575701">"प्रणाली UI ट्युनरले तपाईँलाई Android प्रयोगकर्ता इन्टरफेस आफू अनुकूल गर्न र ट्विक गर्न थप तरिकाहरू प्रदान गर्छ। यी प्रयोगात्मक सुविधाहरू भावी विमोचनमा परिवर्तन हुन, बिग्रिन वा हराउन सक्ने छन्। सावधानीपूर्वक अगाडि बढ्नुहोस्।"</string>
     <string name="tuner_persistent_warning" msgid="8597333795565621795">"यी प्रयोगात्मक सुविधाहरू भावी विमोचनहरूमा परिवर्तन हुन, बिग्रन वा  हराउन सक्छन्। सावधानीपूर्वक अगाडि बढ्नुहोस्।"</string>
     <string name="got_it" msgid="2239653834387972602">"बुझेँ"</string>
     <string name="tuner_toast" msgid="603429811084428439">"बधाईँ छ! सेटिङहरूमा प्रणाली UI ट्युनर थप गरिएको छ"</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..1d7ac5ec 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>
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Minder urgente meldingen onderaan"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Tik nogmaals om te openen"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Veeg omhoog om te ontgrendelen"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Dit apparaat wordt beheerd"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Dit apparaat wordt beheerd door <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Vegen voor telefoon"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Vegen vanaf pictogram voor spraakassistent"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Vegen voor camera"</string>
@@ -451,6 +453,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..bdb1e43 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -70,7 +70,7 @@
     <string name="screenshot_saving_ticker" msgid="7403652894056693515">"ਸਕ੍ਰੀਨਸ਼ੌਟ ਸੁਰੱਖਿਅਤ ਕਰ ਰਿਹਾ ਹੈ…"</string>
     <string name="screenshot_saving_title" msgid="8242282144535555697">"ਸਕ੍ਰੀਨਸ਼ੌਟ ਸੁਰੱਖਿਅਤ ਕਰ ਰਿਹਾ ਹੈ…"</string>
     <string name="screenshot_saving_text" msgid="2419718443411738818">"ਸਕ੍ਰੀਨਸ਼ੌਟ ਸੁਰੱਖਿਅਤ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ।"</string>
-    <string name="screenshot_saved_title" msgid="6461865960961414961">"ਸਕ੍ਰੀਨਸ਼ੌਟ ਕੈਪਚਰ ਕੀਤਾ।"</string>
+    <string name="screenshot_saved_title" msgid="6461865960961414961">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਕੈਪਚਰ ਕੀਤਾ।"</string>
     <string name="screenshot_saved_text" msgid="2685605830386712477">"ਆਪਣਾ ਸਕ੍ਰੀਨਸ਼ਾਟ ਵੇਖਣ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"ਸਕ੍ਰੀਨਸ਼ੌਟ ਕੈਪਚਰ ਨਹੀਂ ਕਰ ਸਕਿਆ।"</string>
     <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਰੱਖਿਅਤ ਕਰਨ ਦੌਰਾਨ ਸਮੱਸਿਆ ਆਈ।"</string>
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"ਹੇਠਾਂ ਘੱਟ ਲਾਜ਼ਮੀ ਸੂਚਨਾਵਾਂ"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"ਖੋਲ੍ਹਣ ਲਈ ਦੁਬਾਰਾ ਟੈਪ ਕਰੋ"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"ਅਨਲੌਕ ਕਰਨ ਲਈ ਉੱਪਰ ਸਵਾਈਪ ਕਰੋ।"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"ਇਹ ਡੀਵਾਈਸ ਪ੍ਰਬੰਧਿਤ ਕੀਤੀ ਗਈ ਹੈ"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"ਇਹ ਡੀਵਾਈਸ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤੀ ਗਈ ਹੈ"</string>
     <string name="phone_hint" msgid="4872890986869209950">"ਫ਼ੋਨ ਲਈ ਆਈਕਨ ਤੋਂ ਸਵਾਈਪ ਕਰੋ"</string>
     <string name="voice_hint" msgid="8939888732119726665">"ਵੌਇਸ ਅਸਿਸਟ ਲਈ ਆਈਕਨ ਤੋਂ ਸਵਾਈਪ ਕਰੋ"</string>
     <string name="camera_hint" msgid="7939688436797157483">"ਕੈਮਰੇ ਲਈ ਆਈਕਨ ਤੋਂ ਸਵਾਈਪ ਕਰੋ"</string>
@@ -395,7 +397,7 @@
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"ਬੈਟਰੀ ਸੇਵਰ ਬੰਦ ਕਰੋ"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ਉਹ ਸਭ ਕੁਝ ਕੈਪਚਰ ਕਰਨਾ ਸ਼ੁਰੂ ਕਰ ਦੇਵੇਗਾ, ਜੋ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ ਤੇ ਡਿਸਪਲੇ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"ਦੁਬਾਰਾ ਨਾ ਦਿਖਾਓ"</string>
-    <string name="clear_all_notifications_text" msgid="814192889771462828">"ਸਾਰੇ ਹਟਾਓ"</string>
+    <string name="clear_all_notifications_text" msgid="814192889771462828">"ਸਭ ਸਾਫ਼ ਕਰੋ"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"ਹੁਣ ਚਾਲੂ ਕਰੋ"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"ਕੋਈ ਸੂਚਨਾਵਾਂ ਨਹੀਂ"</string>
     <string name="device_owned_footer" msgid="3802752663326030053">"ਡੀਵਾਈਸ ਦਾ ਨਿਰੀਖਣ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ"</string>
@@ -451,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-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 78c6102..0bd9179 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -354,6 +354,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Poniżej widać mniej pilne powiadomienia"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Kliknij ponownie, by otworzyć"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Przesuń w górę, by odblokować"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"To urządzenie jest zarządzane"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Tym urządzeniem zarządza <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Aby włączyć telefon, przesuń palcem od ikony"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Aby uzyskać pomoc głosową, przesuń palcem od ikony"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Przesuń palcem od ikony, by włączyć aparat"</string>
@@ -399,7 +401,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 +457,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..ab107e8 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -352,6 +352,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Notificações menos urgentes abaixo"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Toque novamente para abrir"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Deslize para cima para desbloquear"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Este dispositivo é gerenciado"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Este dispositivo é gerenciado por <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Deslize a partir do ícone do telefone"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Deslize a partir do ícone de assistência de voz"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Deslize a partir do ícone da câmera"</string>
@@ -453,6 +455,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..ac34f24 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Notificações menos urgentes abaixo"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Toque novamente para abrir"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Deslizar rapidamente com o dedo para cima para desbloquear"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Este dispositivo é gerido"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Este dispositivo é gerido por <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Deslize rapid. a partir do ícone para aceder ao telemóvel"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Deslize rapid. a partir do ícone para aceder ao assist. voz"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Deslize rapidamente a partir do ícone para aceder à câmara"</string>
@@ -451,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 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..ab107e8 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -352,6 +352,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Notificações menos urgentes abaixo"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Toque novamente para abrir"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Deslize para cima para desbloquear"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Este dispositivo é gerenciado"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Este dispositivo é gerenciado por <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Deslize a partir do ícone do telefone"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Deslize a partir do ícone de assistência de voz"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Deslize a partir do ícone da câmera"</string>
@@ -453,6 +455,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..d18629f 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -354,6 +354,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Notificările mai puțin urgente mai jos"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Atingeți din nou pentru a deschide"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Glisați în sus pentru a debloca"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Acest dispozitiv este gestionat"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Acest dispozitiv este gestionat de <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Glisați dinspre telefon"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Glisați dinspre pictogramă pentru asistentul vocal"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Glisați pentru a fotografia"</string>
@@ -455,6 +457,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Accesibilitate"</item>
   </string-array>
     <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>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 0fbb0bd..bfd75e9 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -356,6 +356,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Показать менее важные оповещения"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Нажмите ещё раз, чтобы открыть"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Проведите вверх, чтобы разблокировать"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Это управляемое устройство"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Этим устройством управляет компания \"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>\""</string>
     <string name="phone_hint" msgid="4872890986869209950">"Телефон: проведите от значка"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Аудиоподсказки: проведите от значка"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Камера: проведите от значка"</string>
@@ -457,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-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index c4d2378..d31d17b 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>
@@ -342,21 +342,23 @@
     <string name="description_target_search" msgid="3091587249776033139">"සෙවීම"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> සඳහා උඩට සර්පණය කරන්න."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> සඳහා වමට සර්පණය කරන්න."</string>
-    <string name="zen_priority_introduction" msgid="3070506961866919502">"එලාම, සිහි කැඳවීම්, සිදුවීම් සහ ඔබ සඳහන් කරන අමතන්නන් වෙතින් හැර, වෙනත් ශබ්ද සහ කම්පනවලින් ඔබට බාධා නොවනු ඇත."</string>
+    <string name="zen_priority_introduction" msgid="3070506961866919502">"එලාම, සිහිකැඳවීම්, සිදුවීම් සහ ඔබ සඳහන් කරන අමතන්නන් වෙතින් හැර, ශබ්ද සහ කම්පනවලින් ඔබට බාධා නොවනු ඇත."</string>
     <string name="zen_priority_customize_button" msgid="7948043278226955063">"අභිරුචිකරණය"</string>
-    <string name="zen_silence_introduction_voice" msgid="2284540992298200729">"මෙය සීනු, සංගීතය, වීඩියෝ, සහ ක්‍රීඩා ඇතුළු, සියලු ශබ්ද සහ කම්පන අවහිර කරයි. ඔබට තවමත් දුරකථන ඇමතුම් සිදු කිරීමේ හැකියාව ඇත."</string>
-    <string name="zen_silence_introduction" msgid="3137882381093271568">"මෙය සීනු, සංගීතය, වීඩියෝ, සහ ක්‍රීඩා ඇතුළු, සියලු ශබ්ද සහ කම්පන අවහිර කරයි."</string>
+    <string name="zen_silence_introduction_voice" msgid="2284540992298200729">"මෙය එලාම්, සංගීතය, වීඩියෝ, සහ ක්‍රීඩා ඇතුළු, සියලු ශබ්ද සහ කම්පන අවහිර කරයි. ඔබට තවමත් දුරකථන ඇමතුම් ගැනීමට හැකියාව ඇත."</string>
+    <string name="zen_silence_introduction" msgid="3137882381093271568">"මෙය එලාම්, සංගීතය, වීඩියෝ, සහ ක්‍රීඩා ඇතුළු, සියලු ශබ්ද සහ කම්පන අවහිර කරයි."</string>
     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
     <string name="speed_bump_explanation" msgid="1288875699658819755">"හදිසිය අඩු දැනුම් දීම් පහත"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"විවෘත කිරීමට නැවත තට්ටු කරන්න"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"අගුළු ඇරීමට ස්වයිප් කරන්න."</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"මෙම උපාංගය කළමනාකරණය නොකෙරේ"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"මෙම උපාංගය <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> මගින් කළමනාකරණය කෙරේ"</string>
     <string name="phone_hint" msgid="4872890986869209950">"දුරකථනය සඳහා නිරූපකය වෙතින් ස්වයිප් කරන්න"</string>
     <string name="voice_hint" msgid="8939888732119726665">"හඬ සහාය සඳහා නිරූපකය වෙතින් ස්වයිප් කරන්න"</string>
     <string name="camera_hint" msgid="7939688436797157483">"කැමරාව සඳහා නිරූපකය වෙතින් ස්වයිප් කරන්න"</string>
     <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 +372,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>
@@ -451,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>
@@ -602,7 +605,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..94eb561 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -356,6 +356,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Menej naliehavé upozornenia sa nachádzajú nižšie"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Upozornenie otvoríte opätovným klepnutím"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Odomknete prejdením prstom nahor"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Toto zariadenie je spravované"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Toto zariadenie spravuje organizácia <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Telefón otvoríte prejdením prstom od ikony"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Hlasového asistenta otvoríte prejdením prstom od ikony"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Fotoaparát otvoríte prejdením prstom od ikony"</string>
@@ -457,6 +459,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..ffbf4ff 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -356,6 +356,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Manj nujna obvestila spodaj"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Znova se dotaknite, da odprete"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Povlecite, da odklenete"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Ta naprava je upravljana"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"To napravo upravlja <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Povlecite z ikone za telefon"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Povlecite z ikone za glasovnega pomočnika"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Povlecite z ikone za fotoaparat"</string>
@@ -457,6 +459,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Funkcije za ljudi s posebnimi potrebami"</item>
   </string-array>
     <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>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index 9616c07..9b0b832 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Njoftimet më pak urgjente, më poshtë!"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Trokit përsëri për ta hapur"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Rrëshqit për të shkyçur"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Kjo është një pajisje e menaxhuar"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Kjo pajisje menaxhohet nga <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Rrëshqit për të hapur telefonin"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Rrëshqit për të hapur ndihmën zanore"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Rrëshqit për të hapur kamerën"</string>
@@ -451,6 +453,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Qasshmëria"</item>
   </string-array>
     <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>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 667c65d..bf875e9 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -352,6 +352,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Мање хитна обавештења су у наставку"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Додирните поново да бисте отворили"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Превуците нагоре да бисте откључали"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Овим уређајем се управља"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Овим уређајем управља <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Превуците од иконе за телефон"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Превуците од иконе за гласовну помоћ"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Превуците од иконе за камеру"</string>
@@ -453,6 +455,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..6c4ee21 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Mindre brådskande aviseringar nedan"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Tryck igen för att öppna"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Svep uppåt för att låsa upp"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Den här enheten är hanterad"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Den här enheten hanteras av <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Svep från ikonen och öppna telefonen"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Svep från ikonen och öppna röstassistenten"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Svep från ikonen och öppna kameran"</string>
@@ -451,6 +453,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..e03615a 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Arifa zisizo za dharura sana ziko hapo chini"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Gonga tena ili ufungue"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Telezesha kidole ili ufungue"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Kifaa hiki kinadhibitiwa"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Kifaa hiki kinadhibitiwa na <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Telezesha kidole kutoka kwa aikoni ili ufikie simu"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Telezesha kidole kutoka aikoni ili upate mapendekezo ya sauti"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Telezesha kidole kutoka aikoni ili ufikie kamera"</string>
@@ -451,6 +453,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..60f1d6a 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"அவசர நிலைக் குறைவான அறிவிப்புகள் கீழே உள்ளன"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"திறக்க, மீண்டும் தட்டவும்"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"திறக்க, மேலே ஸ்வைப் செய்யவும்"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"இந்தச் சாதனத்தை நிர்வகிப்பது:"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"இந்தச் சாதனத்தை நிர்வகிப்பது: <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"ஃபோனிற்கு ஐகானிலிருந்து ஸ்வைப் செய்யவும்"</string>
     <string name="voice_hint" msgid="8939888732119726665">"குரல் உதவிக்கு ஐகானிலிருந்து ஸ்வைப் செய்யவும்"</string>
     <string name="camera_hint" msgid="7939688436797157483">"கேமராவிற்கு ஐகானிலிருந்து ஸ்வைப் செய்யவும்"</string>
@@ -451,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-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index c1aeb09..f500fc2 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"తక్కువ అత్యవసర నోటిఫికేషన్‌లు దిగువన"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"తెరవడానికి మళ్లీ నొక్కండి"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"అన్‌లాక్ చేయడానికి ఎగువకు స్వైప్ చేయండి"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"ఈ పరికరం నిర్వహణలో ఉంది"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"ఈ పరికరం <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> నిర్వహణలో ఉంది"</string>
     <string name="phone_hint" msgid="4872890986869209950">"ఫోన్ కోసం చిహ్నాన్ని స్వైప్ చేయండి"</string>
     <string name="voice_hint" msgid="8939888732119726665">"వాయిస్ సహాయకం చిహ్నం నుండి స్వైప్"</string>
     <string name="camera_hint" msgid="7939688436797157483">"కెమెరా కోసం చిహ్నాన్ని స్వైప్ చేయండి"</string>
@@ -451,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-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 0c461b4..e4d39b7 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"การแจ้งเตือนที่เร่งด่วนน้อยด้านล่าง"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"แตะอีกครั้งเพื่อเปิด"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"เลื่อนเพื่อปลดล็อก"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"อุปกรณ์เครื่องนี้มีการจัดการ"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"อุปกรณ์เครื่องนี้จัดการโดย <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"เลื่อนไอคอนโทรศัพท์"</string>
     <string name="voice_hint" msgid="8939888732119726665">"เลื่อนไอคอนตัวช่วยเสียง"</string>
     <string name="camera_hint" msgid="7939688436797157483">"เลื่อนไอคอนกล้อง"</string>
@@ -451,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-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index caa9f97..de81f71 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Nasa ibaba ang mga notification na hindi masyadong mahalaga"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"I-tap ulit upang buksan"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"I-swipe pataas upang i-unlock"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Pinamamahalaan ang device na ito"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Pinamamahalaan ng <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ang device na ito"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Mag-swipe mula sa icon para sa telepono"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Mag-swipe mula sa icon para sa voice assist"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Mag-swipe mula sa icon para sa camera"</string>
@@ -451,6 +453,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Pagiging Naa-access"</item>
   </string-array>
     <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>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 030c97f..c6e4909 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Daha az acil bildirimler aşağıdadır"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Açmak için tekrar dokunun"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Kilidi açmak için hızlıca yukarı kaydırın"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Bu cihaz yönetilen bir cihazdır"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Bu cihaz <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> tarafından yönetilmektedir."</string>
     <string name="phone_hint" msgid="4872890986869209950">"Telefon için, simgeden hızlıca kaydırın"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Sesli yardım için, simgeden hızlıca kaydırın"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Kamera için, simgeden hızlıca kaydırın"</string>
@@ -451,6 +453,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Erişilebilirlik"</item>
   </string-array>
     <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>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index c086fff..21f9e0e 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -356,6 +356,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Менше термінових сповіщень нижче"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Торкніться знову, щоб відкрити"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Проведіть пальцем угору, щоб розблокувати"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Цим пристроєм керує адміністратор"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Цим пристроєм керує організація <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Телефон: проведіть пальцем від значка"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Голосові підказки: проведіть пальцем від значка"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Камера: проведіть пальцем від значка"</string>
@@ -457,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-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index ff46ad3..0bf112e 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"کم اہم اطلاعات ذیل میں ہیں"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"کھولنے کیلئے دوبارہ تھپتھپائیں"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"غیر مقفل کرنے کیلئے اوپر سوائپ کریں"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"یہ آلہ زیر انتظام ہے"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"یہ آلہ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> کے زیر انتظام ہے"</string>
     <string name="phone_hint" msgid="4872890986869209950">"فون کیلئے آئیکن سے سوائپ کریں"</string>
     <string name="voice_hint" msgid="8939888732119726665">"صوتی معاون کیلئے آئیکن سے سوائپ کریں"</string>
     <string name="camera_hint" msgid="7939688436797157483">"کیمرہ کیلئے آئیکن سے سوائپ کریں"</string>
@@ -451,10 +453,11 @@
     <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۔ ارتعاش پر سیٹ کرنے کیلئے تھپتھپائیں۔ Accessibility سروسز شاید خاموش ہوں۔"</string>
-    <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"‏‎%1$s۔ خاموش کرنے کیلئے تھپتھپائیں۔ Accessibility سروسز شاید خاموش ہوں۔"</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>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"‏%s والیوم کے کنٹرولز دکھائے جا رہے ہیں۔ برخاست کرنے کیلئے سوائپ کریں۔"</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"والیوم کے کنٹرولز مخفی ہیں"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"‏سسٹم UI ٹیونر"</string>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index f2d2661..591b98a 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -352,6 +352,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Kam ahamiyatli bildirishnomalarni pastda ko‘rsatish"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Ochish uchun yana bosing"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Qulfdan chiqarish uchun tepaga suring"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Bu – boshqariladigan qurilma"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Bu – <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> tomonidan boshqariladigan qurilma"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Telefonni ochish uchun suring"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Ovozli yordam: belgidan boshlab suring"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Kamerani ochish uchun suring"</string>
@@ -453,6 +455,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..8b6ea67 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Thông báo ít khẩn cấp hơn bên dưới"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Nhấn lại để mở"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Vuốt lên để mở khóa"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Thiết bị này được quản lý"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Thiết bị này được <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> quản lý"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Vuốt từ biểu tượng để mở điện thoại"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Vuốt từ biểu tượng để mở trợ lý thoại"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Vuốt từ biểu tượng để mở máy ảnh"</string>
@@ -451,6 +453,7 @@
     <item msgid="2919807739709798970"></item>
     <item msgid="150349973435223405"></item>
     <item msgid="6761963760295549099"></item>
+    <item msgid="8119402510273906841">"Trợ năng"</item>
   </string-array>
     <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>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 94c3af1..172c107 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"不太紧急的通知会显示在下方"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"再次点按即可打开"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"向上滑动即可解锁"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"此设备已受到托管"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"此设备是由<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>托管"</string>
     <string name="phone_hint" msgid="4872890986869209950">"滑动图标即可拨打电话"</string>
     <string name="voice_hint" msgid="8939888732119726665">"滑动图标即可打开语音助理"</string>
     <string name="camera_hint" msgid="7939688436797157483">"滑动图标即可打开相机"</string>
@@ -451,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-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 5785af9..afae1ee 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -352,6 +352,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"不太緊急的通知會在下方顯示"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"再次輕按即可開啟"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"向上快速滑動即可解鎖"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"此裝置已受管理"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"此裝置由<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>管理"</string>
     <string name="phone_hint" msgid="4872890986869209950">"從圖示快速滑動即可使用手機功能"</string>
     <string name="voice_hint" msgid="8939888732119726665">"從圖示快速滑動即可使用語音助手"</string>
     <string name="camera_hint" msgid="7939688436797157483">"從圖示快速滑動即可使用相機功能"</string>
@@ -453,6 +455,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-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 6562b39..17946f3 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"較不緊急的通知會顯示在下方"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"再次輕觸即可開啟"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"向上滑動即可解鎖"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"這個裝置受到管理"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"這個裝置是由 <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> 所管理"</string>
     <string name="phone_hint" msgid="4872890986869209950">"滑動手機圖示即可啟用"</string>
     <string name="voice_hint" msgid="8939888732119726665">"滑動語音小幫手圖示即可啟用"</string>
     <string name="camera_hint" msgid="7939688436797157483">"滑動相機圖示即可啟用"</string>
@@ -451,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-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index e3c419b..9d76dc3 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -350,6 +350,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Izaziso ezingasheshi kakhulu ezingezansi"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Thepha futhi ukuze uvule"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Swayiphela phezulu ukuze uvule"</string>
+    <string name="do_disclosure_generic" msgid="8498005633306135779">"Le divayisi iphethwe"</string>
+    <string name="do_disclosure_with_name" msgid="5640615509915445501">"Le divayisi iphethwe yi-<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Swayiphela ifoni kusukela kusithonjana"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Swayiphela isilekeleli sezwi kusukela kusithonjana"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Swayiphela ikhamela kusukela kusithonjana"</string>
@@ -451,6 +453,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 2f7174a..29b5b62 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -81,8 +81,18 @@
     <!-- Height of a heads up notification in the status bar -->
     <dimen name="notification_max_heads_up_height">148dp</dimen>
 
-    <!-- Height of a the summary ("more card") notification on keyguard. -->
-    <dimen name="notification_summary_height">44dp</dimen>
+    <!-- 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>
+
+    <!-- The amount the content shifts upwards when transforming into the icon -->
+    <dimen name="notification_icon_transform_content_shift">32dp</dimen>
 
     <!-- Minimum layouted height of a notification in the statusbar-->
     <dimen name="min_notification_layout_height">48dp</dimen>
@@ -94,7 +104,7 @@
     <dimen name="notification_gear_padding">20dp</dimen>
 
     <!-- size at which Notification icons will be drawn in the status bar -->
-    <dimen name="status_bar_icon_drawing_size">17dip</dimen>
+    <dimen name="status_bar_icon_drawing_size">17dp</dimen>
 
     <!-- opacity at which Notification icons will be drawn in the status bar -->
     <item type="dimen" name="status_bar_icon_drawing_alpha">90%</item>
@@ -102,6 +112,15 @@
     <!-- gap on either side of status bar notification icons -->
     <dimen name="status_bar_icon_padding">0dp</dimen>
 
+    <!-- the padding on the start of the statusbar -->
+    <dimen name="status_bar_padding_start">6dp</dimen>
+
+    <!-- the radius of the overflow dot in the status bar -->
+    <dimen name="overflow_dot_radius">1dp</dimen>
+
+    <!-- the padding between dots in the icon overflow -->
+    <dimen name="overflow_icon_dot_padding">3dp</dimen>
+
     <!-- The padding on the global screenshot background image -->
     <dimen name="global_screenshot_bg_padding">20dp</dimen>
 
@@ -110,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>
 
@@ -257,16 +273,10 @@
     <!-- Default distance from each snap target that GlowPadView considers a "hit" -->
     <dimen name="glowpadview_inner_radius">15dip</dimen>
 
-    <!-- Space reserved for the cards behind the top card in the bottom stack -->
-    <dimen name="bottom_stack_peek_amount">12dp</dimen>
-
     <!-- bottom_stack_peek_amount + notification_min_height
          + notification_collapse_second_card_padding -->
     <dimen name="min_stack_height">104dp</dimen>
 
-    <!-- The height of the area before the bottom stack in which the notifications slow down -->
-    <dimen name="bottom_stack_slow_down_length">12dp</dimen>
-
     <!-- Z distance between notifications if they are in the stack -->
     <dimen name="z_distance_between_notifications">0.5dp</dimen>
 
@@ -474,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/ids.xml b/packages/SystemUI/res/values/ids.xml
index 94d79f2..8c80c71 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -16,18 +16,21 @@
   -->
 
 <resources>
+    <item type="id" name="translation_x_animator_tag"/>
     <item type="id" name="translation_y_animator_tag"/>
     <item type="id" name="translation_z_animator_tag"/>
     <item type="id" name="alpha_animator_tag"/>
     <item type="id" name="top_inset_animator_tag"/>
     <item type="id" name="height_animator_tag"/>
     <item type="id" name="shadow_alpha_animator_tag"/>
+    <item type="id" name="translation_x_animator_end_value_tag"/>
     <item type="id" name="translation_y_animator_end_value_tag"/>
     <item type="id" name="translation_z_animator_end_value_tag"/>
     <item type="id" name="alpha_animator_end_value_tag"/>
     <item type="id" name="top_inset_animator_end_value_tag"/>
     <item type="id" name="height_animator_end_value_tag"/>
     <item type="id" name="shadow_alpha_animator_end_value_tag"/>
+    <item type="id" name="translation_x_animator_start_value_tag"/>
     <item type="id" name="translation_y_animator_start_value_tag"/>
     <item type="id" name="translation_z_animator_start_value_tag"/>
     <item type="id" name="alpha_animator_start_value_tag"/>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 331d09e..c8b3b69d 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 and in Quick Settings footer 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 and in Quick Settings footer 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>
 
@@ -986,9 +992,6 @@
     <!-- Text which is shown in the notification shade when there are no notifications. [CHAR LIMIT=30] -->
     <string name="empty_shade_text">No notifications</string>
 
-    <!-- Footer device owned text [CHAR LIMIT=50] -->
-    <string name="device_owned_footer">Device may be monitored</string>
-
     <!-- Footer profile owned text [CHAR LIMIT=50] -->
     <string name="profile_owned_footer">Profile may be monitored</string>
 
@@ -1013,15 +1016,27 @@
     <!-- Monitoring dialog disconnect vpn button [CHAR LIMIT=30] -->
     <string name="disconnect_vpn">Disconnect VPN</string>
 
-    <!-- Monitoring dialog device owner body text [CHAR LIMIT=400] -->
-    <string name="monitoring_description_device_owned">Your device is managed by <xliff:g id="organization">%1$s</xliff:g>.\n\nYour administrator can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information. For more information, contact your administrator.</string>
+    <!-- Monitoring dialog: Header indicating that the device is managed by a Device Owner app [CHAR LIMIT=80] -->
+    <string name="monitoring_description_do_header_generic">Your device is managed by <xliff:g id="device_owner_app" example="Google Mobile Management">%1$s</xliff:g>.</string>
+
+    <!-- Monitoring dialog: Header indicating that the device is managed by a Device Owner app [CHAR LIMIT=60] -->
+    <string name="monitoring_description_do_header_with_name"><xliff:g id="organization_name" example="Foo, Inc.">%1$s</xliff:g> uses <xliff:g id="device_owner_app" example="Google Mobile Management">%2$s</xliff:g> to manage your device.</string>
+
+    <!-- Monitoring dialog: Part of text body explaining what a Device Owner app can do [CHAR LIMIT=130] -->
+    <string name="monitoring_description_do_body">Your administrator can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.</string>
+
+    <!-- Monitoring dialog: Part of text body explaining that a VPN is connected and what it can do, for devices managed by a Device Owner app [CHAR LIMIT=130] -->
+    <string name="monitoring_description_do_body_vpn">You\'re connected to <xliff:g id="vpn_app">%1$s</xliff:g>, which can monitor your network activity, including emails, apps, and websites.</string>
+
+    <!-- Monitoring dialog: Space that separates the body text and the "learn more" link that follows it. [CHAR LIMIT=5] -->
+    <string name="monitoring_description_do_learn_more_separator">" "</string>
+
+    <!-- Monitoring dialog: Link to learn more about what a Device Owner app can do [CHAR LIMIT=55] -->
+    <string name="monitoring_description_do_learn_more">Learn more</string>
 
     <!-- Monitoring dialog VPN text [CHAR LIMIT=400] -->
     <string name="monitoring_description_vpn">You gave an app permission to set up a VPN connection.\n\nThis app can monitor your device and network activity, including emails, apps, and websites.</string>
 
-    <!-- Monitoring dialog VPN with device owner text [CHAR LIMIT=400] -->
-    <string name="monitoring_description_vpn_device_owned">Your device is managed by <xliff:g id="organization">%1$s</xliff:g>.\n\nYour administrator can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nYou\'re connected to a VPN, which can monitor your network activity, including emails, apps, and websites.\n\nFor more information, contact your administrator.</string>
-
     <!-- Monitoring dialog VPN with profile owner text [CHAR LIMIT=400] -->
     <string name="monitoring_description_vpn_profile_owned">Your work profile is managed by <xliff:g id="organization">%1$s</xliff:g>.\n\nYour administrator is capable of monitoring your network activity including emails, apps, and websites.\n\nFor more information, contact your administrator.\n\nYou\'re also connected to a VPN, which can monitor your network activity.</string>
 
@@ -1043,9 +1058,6 @@
     <!-- Monitoring dialog text for multiple apps (in personal and work profiles) [CHAR LIMIT=400] -->
     <string name="monitoring_description_app_personal_work">Your work profile is managed by <xliff:g id="organization">%1$s</xliff:g>. It is connected to <xliff:g id="application_work">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps, and websites.\n\nYou\'re also connected to <xliff:g id="application_personal">%3$s</xliff:g>, which can monitor your personal network activity.</string>
 
-    <!-- Monitoring dialog text for single app (with device owner) [CHAR LIMIT=400] -->
-    <string name="monitoring_description_vpn_app_device_owned">Your device is managed by <xliff:g id="organization">%1$s</xliff:g>.\n\nYour administrator can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nYou\'re connected to <xliff:g id="application">%2$s</xliff:g>, which can monitor your network activity, including emails, apps, and websites.\n\nFor more information, contact your administrator.</string>
-
     <!-- Indication on the keyguard that appears when the user disables trust agents until the next time they unlock manually. [CHAR LIMIT=NONE] -->
     <string name="keyguard_indication_trust_disabled">Device will stay locked until you manually unlock</string>
 
@@ -1120,6 +1132,7 @@
         <item></item> <!-- STREAM_SYSTEM_ENFORCED -->
         <item></item> <!-- STREAM_DTMF -->
         <item></item> <!-- STREAM_TTS -->
+        <item>Accessibility</item> <!-- STREAM_ACCESSIBILITY -->
     </string-array>
 
     <string name="volume_stream_muted" translatable="false">%s silent</string>
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 21f68f5..e036128 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -26,6 +26,7 @@
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.R;
 import com.android.systemui.assist.AssistManager;
+import com.android.systemui.keyguard.DismissCallbackRegistry;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.phone.KeyguardBouncer;
@@ -89,9 +90,10 @@
     }
 
     public KeyguardBouncer createKeyguardBouncer(Context context, ViewMediatorCallback callback,
-            LockPatternUtils lockPatternUtils, StatusBarWindowManager windowManager,
-            ViewGroup container) {
-        return new KeyguardBouncer(context, callback, lockPatternUtils, windowManager, container);
+            LockPatternUtils lockPatternUtils,
+            ViewGroup container, DismissCallbackRegistry dismissCallbackRegistry) {
+        return new KeyguardBouncer(context, callback, lockPatternUtils, container,
+                dismissCallbackRegistry);
     }
 
     public ScrimController createScrimController(ScrimView scrimBehind, ScrimView scrimInFront,
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/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index 951b27f..13e047c 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -56,7 +56,41 @@
         /** Pulse is done showing. Followed by transition to DOZE or DOZE_AOD. */
         DOZE_PULSE_DONE,
         /** Doze is done. DozeService is finished. */
-        FINISH,
+        FINISH;
+
+        boolean canPulse() {
+            switch (this) {
+                case DOZE:
+                case DOZE_AOD:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        boolean staysAwake() {
+            switch (this) {
+                case DOZE_REQUEST_PULSE:
+                case DOZE_PULSING:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        int screenState() {
+            switch (this) {
+                case UNINITIALIZED:
+                case INITIALIZED:
+                case DOZE:
+                    return Display.STATE_OFF;
+                case DOZE_PULSING:
+                case DOZE_AOD:
+                    return Display.STATE_DOZE; // TODO: use STATE_ON if appropriate.
+                default:
+                    return Display.STATE_UNKNOWN;
+            }
+        }
     }
 
     private final Service mDozeService;
@@ -165,52 +199,32 @@
     }
 
     private void validateTransition(State newState) {
-        switch (mState) {
-            case FINISH:
-                Preconditions.checkState(newState == State.FINISH);
-                break;
-            case UNINITIALIZED:
-                Preconditions.checkState(newState == State.INITIALIZED);
-                break;
-        }
-        switch (newState) {
-            case UNINITIALIZED:
-                throw new IllegalArgumentException("can't go to UNINITIALIZED");
-            case INITIALIZED:
-                Preconditions.checkState(mState == State.UNINITIALIZED);
-                break;
-            case DOZE_PULSING:
-                Preconditions.checkState(mState == State.DOZE_REQUEST_PULSE);
-                break;
-            case DOZE_PULSE_DONE:
-                Preconditions.checkState(mState == State.DOZE_PULSING);
-                break;
-            default:
-                break;
-        }
-    }
-
-    private int screenPolicy(State newState) {
-        switch (newState) {
-            case UNINITIALIZED:
-            case INITIALIZED:
-            case DOZE:
-                return Display.STATE_OFF;
-            case DOZE_PULSING:
-            case DOZE_AOD:
-                return Display.STATE_DOZE; // TODO: use STATE_ON if appropriate.
-            default:
-                return Display.STATE_UNKNOWN;
-        }
-    }
-
-    private boolean wakeLockPolicy(State newState) {
-        switch (newState) {
-            case DOZE_REQUEST_PULSE:
-            case DOZE_PULSING:
-                return true;
-            default:
-                return false;
+        try {
+            switch (mState) {
+                case FINISH:
+                    Preconditions.checkState(newState == State.FINISH);
+                    break;
+                case UNINITIALIZED:
+                    Preconditions.checkState(newState == State.INITIALIZED);
+                    break;
+            }
+            switch (newState) {
+                case UNINITIALIZED:
+                    throw new IllegalArgumentException("can't transition to UNINITIALIZED");
+                case INITIALIZED:
+                    Preconditions.checkState(mState == State.UNINITIALIZED);
+                    break;
+                case DOZE_PULSING:
+                    Preconditions.checkState(mState == State.DOZE_REQUEST_PULSE);
+                    break;
+                case DOZE_PULSE_DONE:
+                    Preconditions.checkState(mState == State.DOZE_PULSING);
+                    break;
+                default:
+                    break;
+            }
+        } catch (RuntimeException e) {
+            throw new IllegalStateException("Illegal Transition: " + mState + " -> " + newState, e);
         }
     }
 
@@ -218,22 +232,26 @@
         if (mState == State.FINISH) {
             return State.FINISH;
         }
+        if (requestedState == State.DOZE_REQUEST_PULSE && !mState.canPulse()) {
+            Log.i(TAG, "Dropping pulse request because current state can't pulse: " + mState);
+            return mState;
+        }
         return requestedState;
     }
 
     private void updateWakeLockState(State newState) {
-        boolean newPolicy = wakeLockPolicy(newState);
-        if (mWakeLockHeldForCurrentState && !newPolicy) {
+        boolean staysAwake = newState.staysAwake();
+        if (mWakeLockHeldForCurrentState && !staysAwake) {
             mWakeLock.release();
             mWakeLockHeldForCurrentState = false;
-        } else if (!mWakeLockHeldForCurrentState && newPolicy) {
+        } else if (!mWakeLockHeldForCurrentState && staysAwake) {
             mWakeLock.acquire();
             mWakeLockHeldForCurrentState = true;
         }
     }
 
     private void updateScreenState(State newState) {
-        int state = screenPolicy(newState);
+        int state = newState.screenState();
         if (state != Display.STATE_UNKNOWN) {
             mDozeService.setDozeScreenState(state);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java b/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java
new file mode 100644
index 0000000..262d29d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.keyguard;
+
+import com.android.internal.policy.IKeyguardDismissCallback;
+
+import java.util.ArrayList;
+
+/**
+ * Registry holding the current set of {@link IKeyguardDismissCallback}s.
+ */
+public class DismissCallbackRegistry {
+
+    private final ArrayList<DismissCallbackWrapper> mDismissCallbacks = new ArrayList<>();
+
+    public void addCallback(IKeyguardDismissCallback callback) {
+        mDismissCallbacks.add(new DismissCallbackWrapper(callback));
+    }
+
+    public void notifyDismissCancelled() {
+        for (int i = mDismissCallbacks.size() - 1; i >= 0; i--) {
+            mDismissCallbacks.get(i).notifyDismissCancelled();
+        }
+        mDismissCallbacks.clear();
+    }
+
+    public void notifyDismissSucceeded() {
+        for (int i = mDismissCallbacks.size() - 1; i >= 0; i--) {
+            mDismissCallbacks.get(i).notifyDismissSucceeded();
+        }
+        mDismissCallbacks.clear();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackWrapper.java b/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackWrapper.java
new file mode 100644
index 0000000..8a91144
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackWrapper.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.keyguard;
+
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.policy.IKeyguardDismissCallback;
+
+/**
+ * A light wrapper around {@link IKeyguardDismissCallback} handling {@link RemoteException}s.
+ */
+public class DismissCallbackWrapper {
+
+    private static final String TAG = "DismissCallbackWrapper";
+
+    private IKeyguardDismissCallback mCallback;
+
+    public DismissCallbackWrapper(IKeyguardDismissCallback callback) {
+        mCallback = callback;
+    }
+
+    public void notifyDismissError() {
+        try {
+            mCallback.onDismissError();
+        } catch (RemoteException e) {
+            Log.i(TAG, "Failed to call callback", e);
+        }
+    }
+
+    public void notifyDismissCancelled() {
+        try {
+            mCallback.onDismissCancelled();
+        } catch (RemoteException e) {
+            Log.i(TAG, "Failed to call callback", e);
+        }
+    }
+
+    public void notifyDismissSucceeded() {
+        try {
+            mCallback.onDismissSucceeded();
+        } catch (RemoteException e) {
+            Log.i(TAG, "Failed to call callback", e);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index fe9f55f..3532f41 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -26,6 +26,7 @@
 import android.os.Trace;
 import android.util.Log;
 
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IKeyguardDrawnCallback;
 import com.android.internal.policy.IKeyguardExitCallback;
 import com.android.internal.policy.IKeyguardService;
@@ -89,9 +90,9 @@
         }
 
         @Override // Binder interface
-        public void dismiss(boolean allowWhileOccluded) {
+        public void dismiss(IKeyguardDismissCallback callback) {
             checkPermission();
-            mKeyguardViewMediator.dismiss(allowWhileOccluded);
+            mKeyguardViewMediator.dismiss(callback);
         }
 
         @Override // Binder interface
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 34dc63f..c19e806 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -20,12 +20,12 @@
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
 
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.app.PendingIntent;
-import android.app.SearchManager;
 import android.app.StatusBarManager;
 import android.app.trust.TrustManager;
 import android.content.BroadcastReceiver;
@@ -48,20 +48,20 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.os.storage.StorageManager;
 import android.provider.Settings;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
-import android.view.IWindowManager;
 import android.view.ViewGroup;
-import android.view.WindowManagerGlobal;
 import android.view.WindowManagerPolicy;
 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;
 import com.android.internal.policy.IKeyguardStateCallback;
@@ -252,6 +252,7 @@
      * var being non-null as an indicator that there is an in progress request.
      */
     private IKeyguardExitCallback mExitSecureCallback;
+    private final DismissCallbackRegistry mDismissCallbackRegistry = new DismissCallbackRegistry();
 
     // the properties of the keyguard
 
@@ -326,6 +327,7 @@
 
     private boolean mWakeAndUnlocking;
     private IKeyguardDrawnCallback mDrawnCallback;
+    private boolean mLockWhenSimRemoved;
 
     KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
 
@@ -347,7 +349,7 @@
                 UserInfo info = UserManager.get(mContext).getUserInfo(userId);
                 if (info != null && (info.isGuest() || info.isDemo())) {
                     // If we just switched to a guest, try to dismiss keyguard.
-                    dismiss(false /* allowWhileOccluded */);
+                    dismiss(null /* callback */);
                 }
             }
         }
@@ -416,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,"
@@ -427,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 "
@@ -443,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.");
@@ -453,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();
@@ -515,7 +537,7 @@
                 return;
             }
 
-            tryKeyguardDone(true);
+            tryKeyguardDone();
             if (strongAuth) {
                 mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();
             }
@@ -565,10 +587,7 @@
             Trace.beginSection("KeyguardViewMediator.mViewMediatorCallback#readyForKeyguardDone");
             if (mKeyguardDonePending) {
                 mKeyguardDonePending = false;
-
-                // Somebody has called keyguardDonePending before, which means that we are
-                // authenticated
-                tryKeyguardDone(true);
+                tryKeyguardDone();
             }
             Trace.endSection();
         }
@@ -600,7 +619,7 @@
 
             if (any && !strongAuthTracker.hasUserAuthenticatedSinceBoot()) {
                 return KeyguardSecurityView.PROMPT_REASON_RESTART;
-            } else if (fingerprint && mUpdateMonitor.hasFingerprintUnlockTimedOut(currentUser)) {
+            } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_TIMEOUT) != 0) {
                 return KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
             } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW) != 0) {
                 return KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN;
@@ -1252,16 +1271,21 @@
 
     /**
      * Dismiss the keyguard through the security layers.
-     * @param allowWhileOccluded if true, dismiss the keyguard even if it's currently occluded.
+     * @param callback Callback to be informed about the result
      */
-    public void handleDismiss(boolean allowWhileOccluded) {
-        if (mShowing && (allowWhileOccluded || !mOccluded)) {
+    private void handleDismiss(IKeyguardDismissCallback callback) {
+        if (mShowing) {
+            if (callback != null) {
+                mDismissCallbackRegistry.addCallback(callback);
+            }
             mStatusBarKeyguardViewManager.dismissAndCollapse();
+        } else if (callback != null) {
+            new DismissCallbackWrapper(callback).notifyDismissError();
         }
     }
 
-    public void dismiss(boolean allowWhileOccluded) {
-        mHandler.obtainMessage(DISMISS, allowWhileOccluded ? 1 : 0, 0).sendToTarget();
+    public void dismiss(IKeyguardDismissCallback callback) {
+        mHandler.obtainMessage(DISMISS, callback).sendToTarget();
     }
 
     /**
@@ -1394,12 +1418,12 @@
         }
     };
 
-    public void keyguardDone(boolean authenticated) {
+    public void keyguardDone() {
         Trace.beginSection("KeyguardViewMediator#keyguardDone");
-        if (DEBUG) Log.d(TAG, "keyguardDone(" + authenticated +")");
+        if (DEBUG) Log.d(TAG, "keyguardDone()");
         userActivity();
         EventLog.writeEvent(70000, 2);
-        Message msg = mHandler.obtainMessage(KEYGUARD_DONE, authenticated ? 1 : 0);
+        Message msg = mHandler.obtainMessage(KEYGUARD_DONE);
         mHandler.sendMessage(msg);
         Trace.endSection();
     }
@@ -1455,7 +1479,7 @@
                     break;
                 case KEYGUARD_DONE:
                     Trace.beginSection("KeyguardViewMediator#handleMessage KEYGUARD_DONE");
-                    handleKeyguardDone(msg.arg1 != 0);
+                    handleKeyguardDone();
                     Trace.endSection();
                     break;
                 case KEYGUARD_DONE_DRAWING:
@@ -1474,7 +1498,7 @@
                     }
                     break;
                 case DISMISS:
-                    handleDismiss(msg.arg1 == 1 ? true : false /* allowWhileOccluded */);
+                    handleDismiss((IKeyguardDismissCallback) msg.obj);
                     break;
                 case START_KEYGUARD_EXIT_ANIM:
                     Trace.beginSection("KeyguardViewMediator#handleMessage START_KEYGUARD_EXIT_ANIM");
@@ -1492,9 +1516,9 @@
         }
     };
 
-    private void tryKeyguardDone(boolean authenticated) {
+    private void tryKeyguardDone() {
         if (!mKeyguardDonePending && mHideAnimationRun && !mHideAnimationRunning) {
-            handleKeyguardDone(authenticated);
+            handleKeyguardDone();
         } else if (!mHideAnimationRun) {
             mHideAnimationRun = true;
             mHideAnimationRunning = true;
@@ -1506,7 +1530,7 @@
      * @see #keyguardDone
      * @see #KEYGUARD_DONE
      */
-    private void handleKeyguardDone(boolean authenticated) {
+    private void handleKeyguardDone() {
         Trace.beginSection("KeyguardViewMediator#handleKeyguardDone");
         final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
         if (mLockPatternUtils.isSecure(currentUser)) {
@@ -1517,9 +1541,7 @@
             resetKeyguardDonePendingLocked();
         }
 
-        if (authenticated) {
-            mUpdateMonitor.clearFailedUnlockAttempts();
-        }
+        mUpdateMonitor.clearFailedUnlockAttempts();
         mUpdateMonitor.clearFingerprintRecognized();
 
         if (mGoingToSleep) {
@@ -1528,22 +1550,21 @@
         }
         if (mExitSecureCallback != null) {
             try {
-                mExitSecureCallback.onKeyguardExitResult(authenticated);
+                mExitSecureCallback.onKeyguardExitResult(true /* authenciated */);
             } catch (RemoteException e) {
-                Slog.w(TAG, "Failed to call onKeyguardExitResult(" + authenticated + ")", e);
+                Slog.w(TAG, "Failed to call onKeyguardExitResult()", e);
             }
 
             mExitSecureCallback = null;
 
-            if (authenticated) {
-                // after succesfully exiting securely, no need to reshow
-                // the keyguard when they've released the lock
-                mExternallyEnabled = true;
-                mNeedToReshowWhenReenabled = false;
-                updateInputRestricted();
-            }
+            // after succesfully exiting securely, no need to reshow
+            // the keyguard when they've released the lock
+            mExternallyEnabled = true;
+            mNeedToReshowWhenReenabled = false;
+            updateInputRestricted();
         }
 
+        mDismissCallbackRegistry.notifyDismissSucceeded();
         handleHide();
         Trace.endSection();
     }
@@ -1690,7 +1711,7 @@
 
     private final Runnable mHideAnimationFinishedRunnable = () -> {
         mHideAnimationRunning = false;
-        tryKeyguardDone(true);
+        tryKeyguardDone();
     };
 
     /**
@@ -1777,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;
@@ -1912,7 +1932,7 @@
     public void onWakeAndUnlocking() {
         Trace.beginSection("KeyguardViewMediator#onWakeAndUnlocking");
         mWakeAndUnlocking = true;
-        keyguardDone(true /* authenticated */);
+        keyguardDone();
         Trace.endSection();
     }
 
@@ -1921,7 +1941,8 @@
             ScrimController scrimController,
             FingerprintUnlockController fingerprintUnlockController) {
         mStatusBarKeyguardViewManager.registerStatusBar(phoneStatusBar, container,
-                statusBarWindowManager, scrimController, fingerprintUnlockController);
+                statusBarWindowManager, scrimController, fingerprintUnlockController,
+                mDismissCallbackRegistry);
         return mStatusBarKeyguardViewManager;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index ccb28e9..43308de 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -24,10 +24,15 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.SpannableStringBuilder;
+import android.text.method.LinkMovementMethod;
+import android.text.style.ClickableSpan;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
+import android.view.Window;
 import android.widget.ImageView;
 import android.widget.TextView;
 
@@ -52,12 +57,12 @@
     private SecurityController mSecurityController;
     private AlertDialog mDialog;
     private QSTileHost mHost;
-    private Handler mHandler;
+    protected Handler mHandler;
     private final Handler mMainHandler;
 
     private boolean mIsVisible;
     private boolean mIsIconVisible;
-    private int mFooterTextId;
+    private CharSequence mFooterTextContent = null;
     private int mFooterIconId;
 
     public QSFooter(QSPanel qsPanel, Context context) {
@@ -68,13 +73,14 @@
         mFooterIcon = (ImageView) mRootView.findViewById(R.id.footer_icon);
         mFooterIconId = R.drawable.ic_qs_vpn;
         mContext = context;
-        mMainHandler = new Handler();
+        mMainHandler = new Handler(Looper.getMainLooper());
     }
 
-    public void setHost(QSTileHost host) {
+    public void setHostEnvironment(QSTileHost host, SecurityController securityController,
+            Looper looper) {
         mHost = host;
-        mSecurityController = host.getSecurityController();
-        mHandler = new H(host.getLooper());
+        mSecurityController = securityController;
+        mHandler = new H(looper);
     }
 
     public void setListening(boolean listening) {
@@ -114,14 +120,21 @@
 
     private void handleRefreshState() {
         mIsIconVisible = mSecurityController.isVpnEnabled();
-        // If the device has device owner, show "Device may be monitored", but --
-        // TODO See b/25779452 -- device owner doesn't actually have monitoring power.
         if (mSecurityController.isDeviceManaged()) {
-            mFooterTextId = R.string.device_owned_footer;
+            final CharSequence organizationName =
+                    mSecurityController.getDeviceOwnerOrganizationName();
+            if (organizationName != null) {
+                mFooterTextContent = mContext.getResources().getString(
+                        R.string.do_disclosure_with_name, organizationName);
+            } else {
+                mFooterTextContent =
+                        mContext.getResources().getString(R.string.do_disclosure_generic);
+            }
             mIsVisible = true;
         } else {
             boolean isBranded = mSecurityController.isVpnBranded();
-            mFooterTextId = isBranded ? R.string.branded_vpn_footer : R.string.vpn_footer;
+            mFooterTextContent = mContext.getResources().getText(
+                    isBranded ? R.string.branded_vpn_footer : R.string.vpn_footer);
             // Update the VPN footer icon, if needed.
             int footerIconId = isBranded ? R.drawable.ic_qs_branded_vpn : R.drawable.ic_qs_vpn;
             if (mFooterIconId != footerIconId) {
@@ -142,23 +155,36 @@
     }
 
     private void createDialog() {
-        String deviceOwner = mSecurityController.getDeviceOwnerName();
-        String profileOwner = mSecurityController.getProfileOwnerName();
-        String primaryVpn = mSecurityController.getPrimaryVpnName();
-        String profileVpn = mSecurityController.getProfileVpnName();
-        boolean managed = mSecurityController.hasProfileOwner();
-        boolean isBranded = deviceOwner == null && mSecurityController.isVpnBranded();
+        final String deviceOwnerPackage = mSecurityController.getDeviceOwnerName();
+        final String profileOwnerPackage = mSecurityController.getProfileOwnerName();
+        final String primaryVpn = mSecurityController.getPrimaryVpnName();
+        final String profileVpn = mSecurityController.getProfileVpnName();
+        final CharSequence deviceOwnerOrganization =
+                mSecurityController.getDeviceOwnerOrganizationName();
+        boolean hasProfileOwner = mSecurityController.hasProfileOwner();
+        boolean isBranded = deviceOwnerPackage == null && mSecurityController.isVpnBranded();
 
         mDialog = new SystemUIDialog(mContext);
         if (!isBranded) {
-            mDialog.setTitle(getTitle(deviceOwner));
+            mDialog.setTitle(getTitle(deviceOwnerPackage));
         }
-        mDialog.setMessage(getMessage(deviceOwner, profileOwner, primaryVpn, profileVpn, managed,
-                isBranded));
+        mDialog.setMessage(getMessage(deviceOwnerPackage, profileOwnerPackage, primaryVpn,
+                profileVpn, deviceOwnerOrganization, hasProfileOwner, isBranded));
+
         mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(isBranded), this);
         if (mSecurityController.isVpnEnabled() && !mSecurityController.isVpnRestricted()) {
             mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getSettingsButton(), this);
         }
+
+        // Make the link "learn more" clickable.
+        // TODO: Reaching into SystemUIDialog's internal View hierarchy is ugly and error-prone.
+        // This is a temporary solution. b/33126622 will introduce a custom View hierarchy for this
+        // dialog, allowing us to set the movement method on the appropriate View without any
+        // knowledge of SystemUIDialog's internals.
+        mDialog.create();
+        ((TextView) mDialog.getWindow().findViewById(com.android.internal.R.id.message))
+                .setMovementMethod(new LinkMovementMethod());
+
         mDialog.show();
     }
 
@@ -170,22 +196,35 @@
         return mContext.getString(isBranded ? android.R.string.ok : R.string.quick_settings_done);
     }
 
-    private String getMessage(String deviceOwner, String profileOwner, String primaryVpn,
-            String profileVpn, boolean primaryUserIsManaged, boolean isBranded) {
-        // Show a special warning when the device has device owner, but --
-        // TODO See b/25779452 -- device owner doesn't actually have monitoring power.
-        if (deviceOwner != null) {
-            if (primaryVpn != null) {
-                return mContext.getString(R.string.monitoring_description_vpn_app_device_owned,
-                        deviceOwner, primaryVpn);
+    protected CharSequence getMessage(String deviceOwnerPackage, String profileOwnerPackage,
+            String primaryVpn, String profileVpn, CharSequence deviceOwnerOrganization,
+            boolean hasProfileOwner, boolean isBranded) {
+        if (deviceOwnerPackage != null) {
+            final SpannableStringBuilder message = new SpannableStringBuilder();
+            if (deviceOwnerOrganization != null) {
+                message.append(mContext.getString(
+                        R.string.monitoring_description_do_header_with_name,
+                        deviceOwnerOrganization, deviceOwnerPackage));
             } else {
-                return mContext.getString(R.string.monitoring_description_device_owned,
-                        deviceOwner);
+                message.append(mContext.getString(R.string.monitoring_description_do_header_generic,
+                        deviceOwnerPackage));
             }
+            message.append("\n\n");
+            message.append(mContext.getString(R.string.monitoring_description_do_body));
+            if (primaryVpn != null) {
+                message.append("\n\n");
+                message.append(mContext.getString(R.string.monitoring_description_do_body_vpn,
+                        primaryVpn));
+            }
+            message.append(mContext.getString(
+                    R.string.monitoring_description_do_learn_more_separator));
+            message.append(mContext.getString(R.string.monitoring_description_do_learn_more),
+                    new EnterprisePrivacySpan(), 0);
+            return message;
         } else if (primaryVpn != null) {
             if (profileVpn != null) {
                 return mContext.getString(R.string.monitoring_description_app_personal_work,
-                        profileOwner, profileVpn, primaryVpn);
+                        profileOwnerPackage, profileVpn, primaryVpn);
             } else {
                 if (isBranded) {
                     return mContext.getString(R.string.branded_monitoring_description_app_personal,
@@ -197,10 +236,10 @@
             }
         } else if (profileVpn != null) {
             return mContext.getString(R.string.monitoring_description_app_work,
-                    profileOwner, profileVpn);
-        } else if (profileOwner != null && primaryUserIsManaged) {
+                    profileOwnerPackage, profileVpn);
+        } else if (profileOwnerPackage != null && hasProfileOwner) {
             return mContext.getString(R.string.monitoring_description_device_owned,
-                    profileOwner);
+                    profileOwnerPackage);
         } else {
             // No device owner, no personal VPN, no work VPN, no user owner. Why are we here?
             return null;
@@ -225,8 +264,8 @@
     private final Runnable mUpdateDisplayState = new Runnable() {
         @Override
         public void run() {
-            if (mFooterTextId != 0) {
-                mFooterText.setText(mFooterTextId);
+            if (mFooterTextContent != null) {
+                mFooterText.setText(mFooterTextContent);
             }
             mRootView.setVisibility(mIsVisible ? View.VISIBLE : View.GONE);
             mFooterIcon.setVisibility(mIsIconVisible ? View.VISIBLE : View.INVISIBLE);
@@ -267,4 +306,18 @@
         }
     }
 
+    protected class EnterprisePrivacySpan extends ClickableSpan {
+        @Override
+        public void onClick(View widget) {
+            final Intent intent = new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+            mDialog.dismiss();
+            mContext.startActivity(intent);
+        }
+
+        @Override
+        public boolean equals(Object object) {
+            return object instanceof EnterprisePrivacySpan;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index e55ff70..d8855c8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -179,7 +179,7 @@
         mHost = host;
         mHost.addCallback(this);
         setTiles(mHost.getTiles());
-        mFooter.setHost(host);
+        mFooter.setHostEnvironment(host, host.getSecurityController(), host.getLooper());
         mCustomizePanel = customizer;
         if (mCustomizePanel != null) {
             mCustomizePanel.setHost(mHost);
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 bc46548..d46d267 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -41,7 +41,7 @@
 import com.android.systemui.statusbar.stack.StackStateAnimator;
 
 /**
- * Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer}
+ * Base class for both {@link ExpandableNotificationRow} and {@link NotificationShelf}
  * to implement dimming/activating on Keyguard for the double-tap gesture
  */
 public abstract class ActivatableNotificationView extends ExpandableOutlineView {
@@ -86,6 +86,12 @@
      */
     private static final float DARK_EXIT_SCALE_START = 0.93f;
 
+    /**
+     * A sentinel value when no color should be used. Can be used with {@link #setTintColor(int)}
+     * or {@link #setOverrideTintColor(int, float)}.
+     */
+    protected static final int NO_COLOR = 0;
+
     private static final Interpolator ACTIVATE_INVERSE_INTERPOLATOR
             = new PathInterpolator(0.6f, 0, 0.5f, 1);
     private static final Interpolator ACTIVATE_INVERSE_ALPHA_INTERPOLATOR
@@ -110,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;
@@ -167,10 +177,13 @@
     private int mCurrentBackgroundTint;
     private int mTargetTint;
     private int mStartTint;
+    private int mOverrideTint;
+    private float mOverrideAmount;
 
     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);
@@ -232,7 +245,6 @@
             boolean wasActivated = mActivated;
             result = handleTouchEventDimmed(event);
             if (wasActivated && result && event.getAction() == MotionEvent.ACTION_UP) {
-                mFalsingManager.onNotificationDoubleTap();
                 removeCallbacks(mTapTimeoutRunnable);
             }
         } else {
@@ -283,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 {
@@ -393,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;
@@ -448,9 +482,20 @@
         if (below != mIsBelowSpeedBump) {
             mIsBelowSpeedBump = below;
             updateBackgroundTint();
+            onBelowSpeedBumpChanged();
         }
     }
 
+    protected void onBelowSpeedBumpChanged() {
+    }
+
+    /**
+     * @return whether we are below the speed bump
+     */
+    public boolean isBelowSpeedBump() {
+        return mIsBelowSpeedBump;
+    }
+
     /**
      * Sets the tint color of the background
      */
@@ -466,6 +511,23 @@
         updateBackgroundTint(animated);
     }
 
+    /**
+     * Set an override tint color that is used for the background.
+     *
+     * @param color the color that should be used to tint the background.
+     *              This can be {@link #NO_COLOR} if the tint should be normally computed.
+     * @param overrideAmount a value from 0 to 1 how much the override tint should be used. The
+     *                       background color will then be the interpolation between this and the
+     *                       regular background color, where 1 means the overrideTintColor is fully
+     *                       used and the background color not at all.
+     */
+    public void setOverrideTintColor(int color, float overrideAmount) {
+        mOverrideTint = color;
+        mOverrideAmount = overrideAmount;
+        int newColor = calculateBgColor();
+        setBackgroundTintColor(newColor);
+    }
+
     protected void updateBackgroundTint() {
         updateBackgroundTint(false /* animated */);
     }
@@ -673,6 +735,13 @@
     }
 
     @Override
+    public void setClipBottomAmount(int clipBottomAmount) {
+        super.setClipBottomAmount(clipBottomAmount);
+        mBackgroundNormal.setClipBottomAmount(clipBottomAmount);
+        mBackgroundDimmed.setClipBottomAmount(clipBottomAmount);
+    }
+
+    @Override
     public void performRemoveAnimation(long duration, float translationDirection,
             Runnable onFinishedRunnable) {
         enableAppearDrawing(true);
@@ -841,11 +910,20 @@
     protected abstract View getContentView();
 
     public int calculateBgColor() {
-        return calculateBgColor(true /* withTint */);
+        return calculateBgColor(true /* withTint */, true /* withOverRide */);
     }
 
-    private int calculateBgColor(boolean withTint) {
-        if (withTint && mBgTint != 0) {
+    /**
+     * @param withTint should a possible tint be factored in?
+     * @param withOverRide should the value be interpolated with {@link #mOverrideTint}
+     * @return the calculated background color
+     */
+    private int calculateBgColor(boolean withTint, boolean withOverRide) {
+        if (withOverRide && mOverrideTint != NO_COLOR) {
+            int defaultTint = calculateBgColor(withTint, false);
+            return NotificationUtils.interpolateColors(defaultTint, mOverrideTint, mOverrideAmount);
+        }
+        if (withTint && mBgTint != NO_COLOR) {
             return mBgTint;
         } else if (mShowingLegacyBackground) {
             return mLegacyColor;
@@ -936,7 +1014,7 @@
     }
 
     public int getBackgroundColorWithoutTint() {
-        return calculateBgColor(false /* withTint */);
+        return calculateBgColor(false /* withTint */, false /* withOverride */);
     }
 
     public interface OnActivatedListener {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 20193f7..414ebec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -42,7 +42,6 @@
 import android.database.ContentObserver;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
 import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Bundle;
@@ -258,7 +257,7 @@
     protected boolean mShowLockscreenNotifications;
     protected boolean mAllowLockscreenRemoteInput;
 
-    protected NotificationOverflowContainer mKeyguardIconOverflowContainer;
+    protected NotificationShelf mNotificationShelf;
     protected DismissView mDismissView;
     protected EmptyShadeView mEmptyShadeView;
 
@@ -1025,9 +1024,7 @@
             }
         }
 
-        if (entry.icon != null) {
-            entry.icon.setTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
-        }
+        entry.setIconTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
     }
 
     public boolean isMediaNotification(NotificationData.Entry entry) {
@@ -1076,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);
@@ -1646,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));
                 }
@@ -2160,13 +2157,14 @@
         if (DEBUG) {
             Log.d(TAG, "createNotificationViews(notification=" + sbn);
         }
-        final StatusBarIconView iconView = createIcon(sbn);
-        if (iconView == null) {
-            return null;
+        NotificationData.Entry entry = new NotificationData.Entry(sbn);
+        try {
+            entry.createIcons(mContext, sbn);
+        } catch (NotificationData.IconException exception) {
+            handleNotificationError(sbn, exception.getMessage());
         }
 
         // Construct the expanded view.
-        NotificationData.Entry entry = new NotificationData.Entry(sbn, iconView);
         if (!inflateViews(entry, mStackScroller)) {
             handleNotificationError(sbn, "Couldn't expand RemoteViews for: " + sbn);
             return null;
@@ -2174,33 +2172,6 @@
         return entry;
     }
 
-    public StatusBarIconView createIcon(StatusBarNotification sbn) {
-        // Construct the icon.
-        Notification n = sbn.getNotification();
-        final StatusBarIconView iconView = new StatusBarIconView(mContext,
-                sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), n);
-        iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
-
-        final Icon smallIcon = n.getSmallIcon();
-        if (smallIcon == null) {
-            handleNotificationError(sbn,
-                    "No small icon in notification from " + sbn.getPackageName());
-            return null;
-        }
-        final StatusBarIcon ic = new StatusBarIcon(
-                sbn.getUser(),
-                sbn.getPackageName(),
-                smallIcon,
-                n.iconLevel,
-                n.number,
-                StatusBarIconView.contentDescForNotification(mContext, n));
-        if (!iconView.set(ic)) {
-            handleNotificationError(sbn, "Couldn't create icon: " + ic);
-            return null;
-        }
-        return iconView;
-    }
-
     protected void addNotificationViews(Entry entry, RankingMap ranking) {
         if (entry == null) {
             return;
@@ -2220,17 +2191,16 @@
      * Updates expanded, dimmed and locked states of notification rows.
      */
     protected void updateRowStates() {
-        mKeyguardIconOverflowContainer.getIconsView().removeAllViews();
-
         ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
         final int N = activeNotifications.size();
 
         int visibleNotifications = 0;
         boolean onKeyguard = mState == StatusBarState.KEYGUARD;
-        int maxNotifications = 0;
+        int maxNotifications = -1;
         if (onKeyguard) {
             maxNotifications = getMaxKeyguardNotifications(true /* recompute */);
         }
+        mStackScroller.setMaxDisplayedNotifications(maxNotifications);
         for (int i = 0; i < N; i++) {
             NotificationData.Entry entry = activeNotifications.get(i);
             boolean childNotification = mGroupManager.isChildInGroupWithSummary(entry.notification);
@@ -2249,12 +2219,8 @@
             boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
             if (suppressedSummary
                     || (isLockscreenPublicMode(userId) && !mShowLockscreenNotifications)
-                    || (onKeyguard && !childWithVisibleSummary
-                            && (visibleNotifications >= maxNotifications || !showOnKeyguard))) {
+                    || (onKeyguard && !showOnKeyguard)) {
                 entry.row.setVisibility(View.GONE);
-                if (onKeyguard && showOnKeyguard && !childNotification && !suppressedSummary) {
-                    mKeyguardIconOverflowContainer.getIconsView().addNotification(entry);
-                }
             } else {
                 boolean wasGone = entry.row.getVisibility() == View.GONE;
                 entry.row.setVisibility(View.VISIBLE);
@@ -2269,13 +2235,9 @@
             }
         }
 
-        mStackScroller.updateOverflowContainerVisibility(onKeyguard
-                && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0);
-
         mStackScroller.changeViewPosition(mDismissView, mStackScroller.getChildCount() - 1);
         mStackScroller.changeViewPosition(mEmptyShadeView, mStackScroller.getChildCount() - 2);
-        mStackScroller.changeViewPosition(mKeyguardIconOverflowContainer,
-                mStackScroller.getChildCount() - 3);
+        mStackScroller.changeViewPosition(mNotificationShelf, mStackScroller.getChildCount() - 3);
     }
 
     public boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
@@ -2367,48 +2329,28 @@
         mGroupManager.onEntryUpdated(entry, oldNotification);
 
         boolean updateSuccessful = false;
-        if (applyInPlace) {
-            if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
-            try {
-                if (entry.icon != null) {
-                    // Update the icon
-                    final StatusBarIcon ic = new StatusBarIcon(
-                            notification.getUser(),
-                            notification.getPackageName(),
-                            n.getSmallIcon(),
-                            n.iconLevel,
-                            n.number,
-                            StatusBarIconView.contentDescForNotification(mContext, n));
-                    entry.icon.setNotification(n);
-                    if (!entry.icon.set(ic)) {
-                        handleNotificationError(notification, "Couldn't update icon: " + ic);
-                        return;
-                    }
+        try {
+            if (applyInPlace) {
+                if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
+                try {
+                    entry.updateIcons(mContext, n);
+                    updateNotificationViews(entry, notification);
+                    updateSuccessful = true;
+                } catch (RuntimeException e) {
+                    // It failed to apply cleanly.
+                    Log.w(TAG, "Couldn't reapply views for package " +
+                            notification.getPackageName(), e);
                 }
-                updateNotificationViews(entry, notification);
-                updateSuccessful = true;
             }
-            catch (RuntimeException e) {
-                // It failed to apply cleanly.
-                Log.w(TAG, "Couldn't reapply views for package " +
-                        notification.getPackageName(), e);
+            if (!updateSuccessful) {
+                entry.updateIcons(mContext, n);
+                if (!inflateViews(entry, mStackScroller)) {
+                    handleNotificationError(notification, "Couldn't update remote views for: "
+                            + notification);
+                }
             }
-        }
-        if (!updateSuccessful) {
-            if (DEBUG) Log.d(TAG, "not reusing notification for key: " + key);
-            final StatusBarIcon ic = new StatusBarIcon(
-                    notification.getUser(),
-                    notification.getPackageName(),
-                    n.getSmallIcon(),
-                    n.iconLevel,
-                    n.number,
-                    StatusBarIconView.contentDescForNotification(mContext, n));
-            entry.icon.setNotification(n);
-            entry.icon.set(ic);
-            if (!inflateViews(entry, mStackScroller)) {
-                handleNotificationError(notification, "Couldn't update remote views for: "
-                        + notification);
-            }
+        } catch (NotificationData.IconException e) {
+            handleNotificationError(notification, e.getMessage());
         }
         updateHeadsUp(key, entry, shouldPeek, alertAgain);
         updateNotifications();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
index 1d7bede..5436664 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
@@ -22,12 +22,17 @@
 import android.view.View;
 
 import com.android.systemui.R;
+import com.android.systemui.statusbar.stack.ExpandableViewState;
+import com.android.systemui.statusbar.stack.StackScrollState;
 
 public class DismissView extends StackScrollerDecorView {
+    private final int mClearAllTopPadding;
     private DismissViewButton mDismissButton;
 
     public DismissView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        mClearAllTopPadding = context.getResources().getDimensionPixelSize(
+                R.dimen.clear_all_padding_top);
     }
 
     @Override
@@ -63,4 +68,21 @@
     public boolean isButtonVisible() {
         return mDismissButton.getAlpha() != 0.0f;
     }
+
+    @Override
+    public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
+        return new DismissViewState();
+    }
+
+    public class DismissViewState extends ExpandableViewState {
+        @Override
+        public void applyToView(View view) {
+            super.applyToView(view);
+            if (view instanceof DismissView) {
+                DismissView dismissView = (DismissView) view;
+                boolean visible = this.clipTopAmount < mClearAllTopPadding;
+                dismissView.performVisibilityAnimation(visible && !dismissView.willBeGone());
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
index 5db0699..19b32af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
@@ -23,6 +23,8 @@
 import android.widget.TextView;
 
 import com.android.systemui.R;
+import com.android.systemui.statusbar.stack.ExpandableViewState;
+import com.android.systemui.statusbar.stack.StackScrollState;
 
 public class EmptyShadeView extends StackScrollerDecorView {
 
@@ -40,4 +42,22 @@
     protected View findContentView() {
         return findViewById(R.id.no_notifications);
     }
+
+    @Override
+    public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
+        return new EmptyShadeViewState();
+    }
+
+    public static class EmptyShadeViewState extends ExpandableViewState {
+        @Override
+        public void applyToView(View view) {
+            super.applyToView(view);
+            if (view instanceof EmptyShadeView) {
+                EmptyShadeView emptyShadeView = (EmptyShadeView) view;
+                boolean visible = this.clipTopAmount <= 0;
+                emptyShadeView.performVisibilityAnimation(
+                        visible && !emptyShadeView.willBeGone());
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 5173176..661cc3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -36,6 +36,7 @@
 import android.view.MotionEvent;
 import android.view.NotificationHeaderView;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.ViewStub;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -45,16 +46,18 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.NotificationColorUtil;
+import com.android.internal.widget.CachingIconView;
+import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.statusbar.notification.HybridNotificationView;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.stack.AnimationProperties;
+import com.android.systemui.statusbar.stack.ExpandableViewState;
 import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.stack.StackScrollState;
-import com.android.systemui.statusbar.stack.StackStateAnimator;
-import com.android.systemui.statusbar.stack.StackViewState;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -63,6 +66,8 @@
 
     private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
     private static final int COLORED_DIVIDER_ALPHA = 0x7B;
+    private int mIconTransformContentShift;
+    private int mIconTransformContentShiftNoIcon;
     private int mNotificationMinHeightLegacy;
     private int mMaxHeadsUpHeightLegacy;
     private int mMaxHeadsUpHeight;
@@ -188,6 +193,10 @@
     private View mChildAfterViewWhenDismissed;
     private View mGroupParentWhenDismissed;
     private boolean mRefocusOnDismiss;
+    private float mIconTransformationAmount;
+    private boolean mIconsVisible = true;
+    private boolean mAboveShelf;
+    private boolean mIsLastChild;
 
     public boolean isGroupExpansionChanging() {
         if (isChildInGroup()) {
@@ -293,6 +302,7 @@
         // The public layouts expand button is always visible
         mPublicLayout.updateExpandButtons(true);
         updateLimits();
+        updateIconVisibilities();
     }
 
     private void updateLimits() {
@@ -318,6 +328,10 @@
         return mStatusBarNotification;
     }
 
+    public NotificationData.Entry getEntry() {
+        return mEntry;
+    }
+
     public boolean isHeadsUp() {
         return mIsHeadsUp;
     }
@@ -333,6 +347,9 @@
         if (intrinsicBefore != getIntrinsicHeight()) {
             notifyHeightChanged(false  /* needsAnimation */);
         }
+        if (isHeadsUp) {
+            setAboveShelf(true);
+        }
     }
 
     public void setGroupManager(NotificationGroupManager groupManager) {
@@ -400,6 +417,7 @@
         if (mNotificationParent != null) {
             mNotificationParent.updateBackgroundForGroupState();
         }
+        updateIconVisibilities();
     }
 
     @Override
@@ -459,7 +477,7 @@
 
     public void getChildrenStates(StackScrollState resultState) {
         if (mIsSummaryWithChildren) {
-            StackViewState parentState = resultState.getViewStateForView(this);
+            ExpandableViewState parentState = resultState.getViewStateForView(this);
             mChildrenContainer.getState(resultState, parentState);
         }
     }
@@ -476,11 +494,9 @@
         }
     }
 
-    public void startChildAnimation(StackScrollState finalState,
-            StackStateAnimator stateAnimator, long delay, long duration) {
+    public void startChildAnimation(StackScrollState finalState, AnimationProperties properties) {
         if (mIsSummaryWithChildren) {
-            mChildrenContainer.startAnimationToState(finalState, stateAnimator, delay,
-                    duration);
+            mChildrenContainer.startAnimationToState(finalState, properties);
         }
     }
 
@@ -522,12 +538,17 @@
         return mIsPinned;
     }
 
+    @Override
+    public int getPinnedHeadsUpHeight() {
+        return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
+    }
+
     /**
      * @param atLeastMinHeight should the value returned be at least the minimum height.
      *                         Used to avoid cyclic calls
      * @return the height of the heads up notification when pinned
      */
-    public int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
+    private int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
         if (mIsSummaryWithChildren) {
             return mChildrenContainer.getIntrinsicHeight();
         }
@@ -764,9 +785,17 @@
         return mChildrenContainer;
     }
 
-    public void setHeadsupDisappearRunning(boolean running) {
-        mHeadsupDisappearRunning = running;
-        mPrivateLayout.setHeadsupDisappearRunning(running);
+    public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
+        mHeadsupDisappearRunning = headsUpAnimatingAway;
+        mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
+    }
+
+    /**
+     * @return if the view was just heads upped and is now animating away. During such a time the
+     * layout needs to be kept consistent
+     */
+    public boolean isHeadsUpAnimatingAway() {
+        return mHeadsupDisappearRunning;
     }
 
     public View getChildAfterViewWhenDismissed() {
@@ -785,6 +814,105 @@
         mVetoButton.setOnClickListener(listener);
     }
 
+    public View getNotificationIcon() {
+        NotificationHeaderView notificationHeader = getNotificationHeader();
+        if (notificationHeader != null) {
+            return notificationHeader.getIcon();
+        }
+        return null;
+    }
+
+    /**
+     * @return whether the notification is currently showing a view with an icon.
+     */
+    public boolean isShowingIcon() {
+        if (mIsSummaryWithChildren) {
+            return true;
+        }
+        NotificationContentView showingLayout = getShowingLayout();
+        NotificationHeaderView notificationHeader = showingLayout.getVisibleNotificationHeader();
+        return notificationHeader != null;
+    }
+
+    /**
+     * Set how much this notification is transformed into an icon.
+     *
+     * @param iconTransformationAmount A value from 0 to 1 indicating how much we are transformed
+     *                                 to an icon
+     * @param isLastChild is this the last child in the list. If true, then the transformation is
+     *                    different since it's content fades out.
+     */
+    public void setIconTransformationAmount(float iconTransformationAmount, boolean isLastChild) {
+        boolean changeTransformation = isLastChild != mIsLastChild;
+        changeTransformation |= mIconTransformationAmount != iconTransformationAmount;
+        mIsLastChild = isLastChild;
+        mIconTransformationAmount = iconTransformationAmount;
+        if (changeTransformation) {
+            updateContentTransformation();
+            boolean iconsVisible = mIconTransformationAmount == 0.0f;
+            if (iconsVisible != mIconsVisible) {
+                mIconsVisible = iconsVisible;
+                updateIconVisibilities();
+            }
+        }
+    }
+
+    @Override
+    protected void onBelowSpeedBumpChanged() {
+        updateIconVisibilities();
+    }
+
+    private void updateContentTransformation() {
+        float contentAlpha;
+        float translationY = - mIconTransformationAmount * mIconTransformContentShift;
+        if (mIsLastChild) {
+            contentAlpha = 1.0f - mIconTransformationAmount;
+            contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
+            contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
+            translationY *= 0.4f;
+        } else {
+            contentAlpha = 1.0f;
+        }
+        mPublicLayout.setAlpha(contentAlpha);
+        mPrivateLayout.setAlpha(contentAlpha);
+        mPublicLayout.setTranslationY(translationY);
+        mPrivateLayout.setTranslationY(translationY);
+        if (mChildrenContainer != null) {
+            mChildrenContainer.setAlpha(contentAlpha);
+            mChildrenContainer.setTranslationY(translationY);
+            // TODO: handle children fade out better
+        }
+    }
+
+    private void updateIconVisibilities() {
+        boolean visible = isChildInGroup() || isBelowSpeedBump() || mIconsVisible;
+        mPublicLayout.setIconsVisible(visible);
+        mPrivateLayout.setIconsVisible(visible);
+        if (mChildrenContainer != null) {
+            mChildrenContainer.setIconsVisible(visible);
+        }
+    }
+
+    /**
+     * Get the relative top padding of a view relative to this view. This recursively walks up the
+     * hierarchy and does the corresponding measuring.
+     *
+     * @param view the view to the the padding for. The requested view has to be a child of this
+     *             notification.
+     * @return the toppadding
+     */
+    public int getRelativeTopPadding(View view) {
+        int topPadding = 0;
+        while (view.getParent() instanceof ViewGroup) {
+            topPadding += view.getTop();
+            view = (View) view.getParent();
+            if (view instanceof ExpandableNotificationRow) {
+                return topPadding;
+            }
+        }
+        return topPadding;
+    }
+
     public interface ExpansionLogger {
         public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
     }
@@ -804,6 +932,8 @@
         mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
         mIncreasedPaddingBetweenElements = getResources()
                 .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
+        mIconTransformContentShiftNoIcon = getResources().getDimensionPixelSize(
+                R.dimen.notification_icon_transform_content_shift);
     }
 
     /**
@@ -1276,6 +1406,21 @@
         if (mSettingsIconRow != null) {
             mSettingsIconRow.updateVerticalLocation();
         }
+        updateContentShiftHeight();
+    }
+
+    /**
+     * Updates the content shift height such that the header is completely hidden when coming from
+     * the top.
+     */
+    private void updateContentShiftHeight() {
+        NotificationHeaderView notificationHeader = getNotificationHeader();
+        if (notificationHeader != null) {
+            CachingIconView icon = notificationHeader.getIcon();
+            mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
+        } else {
+            mIconTransformContentShift = mIconTransformContentShiftNoIcon;
+        }
     }
 
     private void updateMaxHeights() {
@@ -1532,6 +1677,19 @@
         }
     }
 
+    @Override
+    public void setClipBottomAmount(int clipBottomAmount) {
+        super.setClipBottomAmount(clipBottomAmount);
+        mPrivateLayout.setClipBottomAmount(clipBottomAmount);
+        mPublicLayout.setClipBottomAmount(clipBottomAmount);
+        if (mGuts != null) {
+            mGuts.setClipBottomAmount(clipBottomAmount);
+        }
+        if (mChildrenContainer != null) {
+            mChildrenContainer.setClipBottomAmount(clipBottomAmount);
+        }
+    }
+
     public boolean isMaxExpandHeightInitialized() {
         return mMaxExpandHeight != 0;
     }
@@ -1679,4 +1837,54 @@
     public interface OnExpandClickListener {
         void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
     }
+
+    @Override
+    public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
+        return new NotificationViewState(stackScrollState);
+    }
+
+    @Override
+    public boolean isAboveShelf() {
+        return mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf);
+    }
+
+    public void setAboveShelf(boolean aboveShelf) {
+        mAboveShelf = aboveShelf;
+    }
+
+    public class NotificationViewState extends ExpandableViewState {
+
+        private final StackScrollState mOverallState;
+
+
+        private NotificationViewState(StackScrollState stackScrollState) {
+            mOverallState = stackScrollState;
+        }
+
+        @Override
+        public void applyToView(View view) {
+            super.applyToView(view);
+            if (view instanceof ExpandableNotificationRow) {
+                ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+                row.applyChildrenState(mOverallState);
+            }
+        }
+
+        @Override
+        protected void onYTranslationAnimationFinished() {
+            super.onYTranslationAnimationFinished();
+            if (mHeadsupDisappearRunning) {
+                setHeadsUpAnimatingAway(false);
+            }
+        }
+
+        @Override
+        public void animateTo(View child, AnimationProperties properties) {
+            super.animateTo(child, properties);
+            if (child instanceof ExpandableNotificationRow) {
+                ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+                row.startChildAnimation(mOverallState, properties);
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index 9d9f3b9..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;
@@ -97,15 +103,23 @@
         if (mCustomOutline) {
             return;
         }
-        boolean hasOutline = true;
-        if (isChildInGroup()) {
-            hasOutline = isGroupExpanded() && !isGroupExpansionChanging();
-        } else if (isSummaryWithChildren()) {
-            hasOutline = !isGroupExpanded() || isGroupExpansionChanging();
-        }
+        boolean hasOutline = needsOutline();
         setOutlineProvider(hasOutline ? mProvider : null);
     }
 
+    /**
+     * @return whether the view currently needs an outline. This is usually false in case it doesn't
+     * have a background.
+     */
+    protected boolean needsOutline() {
+        if (isChildInGroup()) {
+            return isGroupExpanded() && !isGroupExpansionChanging();
+        } else if (isSummaryWithChildren()) {
+            return !isGroupExpanded() || isGroupExpansionChanging();
+        }
+        return true;
+    }
+
     public boolean isOutlineShowing() {
         ViewOutlineProvider op = getOutlineProvider();
         return op != null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 83b0ee0..37a900e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -25,6 +25,8 @@
 import android.widget.FrameLayout;
 
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.stack.ExpandableViewState;
+import com.android.systemui.statusbar.stack.StackScrollState;
 
 import java.util.ArrayList;
 
@@ -36,6 +38,7 @@
     protected OnHeightChangedListener mOnHeightChangedListener;
     private int mActualHeight;
     protected int mClipTopAmount;
+    protected int mClipBottomAmount;
     private boolean mDark;
     private ArrayList<View> mMatchParentViews = new ArrayList<View>();
     private static Rect mClipRect = new Rect();
@@ -44,6 +47,8 @@
     private boolean mClipToActualHeight = true;
     private boolean mChangingPosition = false;
     private ViewGroup mTransientContainer;
+    private boolean mInShelf;
+    private boolean mTransformingInShelf;
 
     public ExpandableView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -220,10 +225,26 @@
         updateClipping();
     }
 
+    /**
+     * Set the amount the the notification is clipped on the bottom in addition to the regular
+     * clipping. This is mainly used to clip something in a non-animated way without changing the
+     * actual height of the notification and is purely visual.
+     *
+     * @param clipBottomAmount the amount to clip.
+     */
+    public void setClipBottomAmount(int clipBottomAmount) {
+        mClipBottomAmount = clipBottomAmount;
+        updateClipping();
+    }
+
     public int getClipTopAmount() {
         return mClipTopAmount;
     }
 
+    public int getClipBottomAmount() {
+        return mClipBottomAmount;
+    }
+
     public void setOnHeightChangedListener(OnHeightChangedListener listener) {
         mOnHeightChangedListener = listener;
     }
@@ -261,9 +282,18 @@
 
     public abstract void performAddAnimation(long delay, long duration);
 
+    /**
+     * Set the notification appearance to be below the speed bump.
+     * @param below true if it is below.
+     */
     public void setBelowSpeedBump(boolean below) {
     }
 
+    public int getPinnedHeadsUpHeight() {
+        return getIntrinsicHeight();
+    }
+
+
     /**
      * Sets the translation of the view.
      */
@@ -324,10 +354,8 @@
     private void updateClipping() {
         if (mClipToActualHeight) {
             int top = getClipTopAmount();
-            if (top >= getActualHeight()) {
-                top = getActualHeight() - 1;
-            }
-            mClipRect.set(0, top, getWidth(), getActualHeight() + getExtraBottomPadding());
+            mClipRect.set(0, top, getWidth(), Math.max(getActualHeight() + getExtraBottomPadding()
+                                - mClipBottomAmount, top));
             setClipBounds(mClipRect);
         } else {
             setClipBounds(null);
@@ -438,6 +466,46 @@
 
     public void setActualHeightAnimating(boolean animating) {}
 
+    public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
+        return new ExpandableViewState();
+    }
+
+    /**
+     * @return whether the current view doesn't add height to the overall content. This means that
+     * if it is added to a list of items, it's content will still have the same height.
+     * An example is the notification shelf, that is always placed on top of another view.
+     */
+    public boolean hasNoContentHeight() {
+        return false;
+    }
+
+    /**
+     * @param inShelf whether the view is currently fully in the notification shelf.
+     */
+    public void setInShelf(boolean inShelf) {
+        mInShelf = inShelf;
+    }
+
+    public boolean isInShelf() {
+        return mInShelf;
+    }
+
+    /**
+     * @param transformingInShelf whether the view is currently transforming into the shelf in an
+     *                            animated way
+     */
+    public void setTransformingInShelf(boolean transformingInShelf) {
+        mTransformingInShelf = transformingInShelf;
+    }
+
+    public boolean isTransformingIntoShelf() {
+        return mTransformingInShelf;
+    }
+
+    public boolean isAboveShelf() {
+        return false;
+    }
+
     /**
      * A listener notifying when {@link #getActualHeight} changes.
      */
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/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
index 8688c28..dea9e31f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
@@ -33,6 +33,7 @@
     private Drawable mBackground;
     private int mClipTopAmount;
     private int mActualHeight;
+    private int mClipBottomAmount;
 
     public NotificationBackgroundView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -44,8 +45,9 @@
     }
 
     private void draw(Canvas canvas, Drawable drawable) {
-        if (drawable != null && mActualHeight > mClipTopAmount) {
-            drawable.setBounds(0, mClipTopAmount, getWidth(), mActualHeight);
+        int bottom = mActualHeight - mClipBottomAmount;
+        if (drawable != null && bottom > mClipTopAmount) {
+            drawable.setBounds(0, mClipTopAmount, getWidth(), bottom);
             drawable.draw(canvas);
         }
     }
@@ -120,6 +122,11 @@
         invalidate();
     }
 
+    public void setClipBottomAmount(int clipBottomAmount) {
+        mClipBottomAmount = clipBottomAmount;
+        invalidate();
+    }
+
     @Override
     public boolean hasOverlappingRendering() {
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 58d57f6..ad6a5db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -121,7 +121,9 @@
 
     private int mContentHeightAtAnimationStart = UNDEFINED;
     private boolean mFocusOnVisibilityChange;
-    private boolean mHeadsupDisappearRunning;
+    private boolean mHeadsUpAnimatingAway;
+    private boolean mIconsVisible;
+    private int mClipBottomAmount;
 
 
     public NotificationContentView(Context context, AttributeSet attrs) {
@@ -456,7 +458,7 @@
                     isTransitioningFromTo(VISIBLE_TYPE_HEADSUP, VISIBLE_TYPE_EXPANDED) ||
                     isTransitioningFromTo(VISIBLE_TYPE_EXPANDED, VISIBLE_TYPE_HEADSUP);
             boolean pinned = !isVisibleOrTransitioning(VISIBLE_TYPE_CONTRACTED)
-                    && (mIsHeadsUp || mHeadsupDisappearRunning);
+                    && (mIsHeadsUp || mHeadsUpAnimatingAway);
             if (transitioningBetweenHunAndExpanded || pinned) {
                 return Math.min(mHeadsUpChild.getHeight(), mExpandedChild.getHeight());
             }
@@ -587,9 +589,24 @@
         updateClipping();
     }
 
+
+    public void setClipBottomAmount(int clipBottomAmount) {
+        mClipBottomAmount = clipBottomAmount;
+        updateClipping();
+    }
+
+    @Override
+    public void setTranslationY(float translationY) {
+        super.setTranslationY(translationY);
+        updateClipping();
+    }
+
     private void updateClipping() {
         if (mClipToActualHeight) {
-            mClipBounds.set(0, mClipTopAmount, getWidth(), mContentHeight);
+            int top = (int) (mClipTopAmount - getTranslationY());
+            int bottom = (int) (mContentHeight - mClipBottomAmount - getTranslationY());
+            bottom = Math.max(top, bottom);
+            mClipBounds.set(0, top, getWidth(), bottom);
             setClipBounds(mClipBounds);
         } else {
             setClipBounds(null);
@@ -840,7 +857,7 @@
             return VISIBLE_TYPE_SINGLELINE;
         }
 
-        if ((mIsHeadsUp || mHeadsupDisappearRunning) && mHeadsUpChild != null) {
+        if ((mIsHeadsUp || mHeadsUpAnimatingAway) && mHeadsUpChild != null) {
             if (viewHeight <= mHeadsUpChild.getHeight() || noExpandedChild) {
                 return VISIBLE_TYPE_HEADSUP;
             } else {
@@ -1183,12 +1200,38 @@
         }
     }
 
-    public void setHeadsupDisappearRunning(boolean headsupDisappearRunning) {
-        mHeadsupDisappearRunning = headsupDisappearRunning;
+    public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
+        mHeadsUpAnimatingAway = headsUpAnimatingAway;
         selectLayout(false /* animate */, true /* force */);
     }
 
     public void setFocusOnVisibilityChange() {
         mFocusOnVisibilityChange = true;
     }
+
+    public void setIconsVisible(boolean iconsVisible) {
+        mIconsVisible = iconsVisible;
+        updateIconVisibilities();
+    }
+
+    private void updateIconVisibilities() {
+        if (mContractedWrapper != null) {
+            NotificationHeaderView header = mContractedWrapper.getNotificationHeader();
+            if (header != null) {
+                header.getIcon().setForceHidden(!mIconsVisible);
+            }
+        }
+        if (mHeadsUpWrapper != null) {
+            NotificationHeaderView header = mHeadsUpWrapper.getNotificationHeader();
+            if (header != null) {
+                header.getIcon().setForceHidden(!mIconsVisible);
+            }
+        }
+        if (mExpandedWrapper != null) {
+            NotificationHeaderView header = mExpandedWrapper.getNotificationHeader();
+            if (header != null) {
+                header.getIcon().setForceHidden(!mIconsVisible);
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 7019880..3687f6d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -19,6 +19,7 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.content.Context;
+import android.graphics.drawable.Icon;
 import android.os.SystemClock;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationListenerService.Ranking;
@@ -26,8 +27,11 @@
 import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
 import android.view.View;
+import android.widget.ImageView;
 import android.widget.RemoteViews;
 
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.util.NotificationColorUtil;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
@@ -48,9 +52,11 @@
     public static final class Entry {
         private static final long LAUNCH_COOLDOWN = 2000;
         private static final long NOT_LAUNCHED_YET = -LAUNCH_COOLDOWN;
+        private static final int COLOR_INVALID = 1;
         public String key;
         public StatusBarNotification notification;
         public StatusBarIconView icon;
+        public StatusBarIconView expandedIcon;
         public ExpandableNotificationRow row; // the outer expanded view
         private boolean interruption;
         public boolean autoRedacted; // whether the redacted notification was generated by us
@@ -62,11 +68,12 @@
         public RemoteViews cachedHeadsUpContentView;
         public RemoteViews cachedPublicContentView;
         public CharSequence remoteInputText;
+        private int mCachedContrastColor = COLOR_INVALID;
+        private int mCachedContrastColorIsFor = COLOR_INVALID;
 
-        public Entry(StatusBarNotification n, StatusBarIconView ic) {
+        public Entry(StatusBarNotification n) {
             this.key = n.getKey();
             this.notification = n;
-            this.icon = ic;
         }
 
         public void setInterruption() {
@@ -165,6 +172,85 @@
         public boolean hasJustLaunchedFullScreenIntent() {
             return SystemClock.elapsedRealtime() < lastFullScreenIntentLaunchTime + LAUNCH_COOLDOWN;
         }
+
+        /**
+         * Create the icons for a notification
+         * @param context the context to create the icons with
+         * @param sbn the notification
+         * @throws IconException
+         */
+        public void createIcons(Context context, StatusBarNotification sbn) throws IconException {
+            Notification n = sbn.getNotification();
+            final Icon smallIcon = n.getSmallIcon();
+            if (smallIcon == null) {
+                throw new IconException("No small icon in notification from "
+                        + sbn.getPackageName());
+            }
+
+            // Construct the icon.
+            icon = new StatusBarIconView(context,
+                    sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), n);
+            icon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+
+            // Construct the expanded icon.
+            expandedIcon = new StatusBarIconView(context,
+                    sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), n);
+            expandedIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+            final StatusBarIcon ic = new StatusBarIcon(
+                    sbn.getUser(),
+                    sbn.getPackageName(),
+                    smallIcon,
+                    n.iconLevel,
+                    n.number,
+                    StatusBarIconView.contentDescForNotification(context, n));
+            if (!icon.set(ic) || !expandedIcon.set(ic)) {
+                icon = null;
+                expandedIcon = null;
+                throw new IconException("Couldn't create icon: " + ic);
+            }
+        }
+
+        public void setIconTag(int key, Object tag) {
+            if (icon != null) {
+                icon.setTag(key, tag);
+                expandedIcon.setTag(key, tag);
+            }
+        }
+
+        /**
+         * Update the notification icons.
+         * @param context the context to create the icons with.
+         * @param n the notification to read the icon from.
+         * @throws IconException
+         */
+        public void updateIcons(Context context, Notification n) throws IconException {
+            if (icon != null) {
+                // Update the icon
+                final StatusBarIcon ic = new StatusBarIcon(
+                        notification.getUser(),
+                        notification.getPackageName(),
+                        n.getSmallIcon(),
+                        n.iconLevel,
+                        n.number,
+                        StatusBarIconView.contentDescForNotification(context, n));
+                icon.setNotification(n);
+                expandedIcon.setNotification(n);
+                if (!icon.set(ic) || !expandedIcon.set(ic)) {
+                    throw new IconException("Couldn't update icon: " + ic);
+                }
+            }
+        }
+
+        public int getContrastedColor(Context context) {
+            int rawColor = notification.getNotification().color;
+            if (mCachedContrastColorIsFor == rawColor && mCachedContrastColor != COLOR_INVALID) {
+                return mCachedContrastColor;
+            }
+            final int contrasted = NotificationColorUtil.resolveContrastColor(context, rawColor);
+            mCachedContrastColorIsFor = rawColor;
+            mCachedContrastColor = contrasted;
+            return mCachedContrastColor;
+        }
     }
 
     private final ArrayMap<String, Entry> mEntries = new ArrayMap<>();
@@ -472,4 +558,10 @@
         public String getCurrentMediaNotificationKey();
         public NotificationGroupManager getGroupManager();
     }
+
+    public static class IconException extends Exception {
+        IconException(String error) {
+            super(error);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index bb327ef..ed1179a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -62,6 +62,7 @@
 
     private Drawable mBackground;
     private int mClipTopAmount;
+    private int mClipBottomAmount;
     private int mActualHeight;
     private boolean mExposed;
     private INotificationManager mINotificationManager;
@@ -136,8 +137,10 @@
     }
 
     private void draw(Canvas canvas, Drawable drawable) {
-        if (drawable != null) {
-            drawable.setBounds(0, mClipTopAmount, getWidth(), mActualHeight);
+        int top = mClipTopAmount;
+        int bottom = mActualHeight - mClipBottomAmount;
+        if (drawable != null && top < bottom) {
+            drawable.setBounds(0, top, getWidth(), bottom);
             drawable.draw(canvas);
         }
     }
@@ -423,6 +426,11 @@
         invalidate();
     }
 
+    public void setClipBottomAmount(int clipBottomAmount) {
+        mClipBottomAmount = clipBottomAmount;
+        invalidate();
+    }
+
     @Override
     public boolean hasOverlappingRendering() {
         // Prevents this view from creating a layer when alpha is animating.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
deleted file mode 100644
index 8e8ce1a..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.TextView;
-
-import com.android.systemui.R;
-import com.android.systemui.ViewInvertHelper;
-import com.android.systemui.statusbar.phone.NotificationPanelView;
-
-/**
- * Container view for overflowing notification icons on Keyguard.
- */
-public class NotificationOverflowContainer extends ActivatableNotificationView {
-
-    private NotificationOverflowIconsView mIconsView;
-    private ViewInvertHelper mViewInvertHelper;
-    private boolean mDark;
-    private View mContent;
-
-    public NotificationOverflowContainer(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mIconsView = (NotificationOverflowIconsView) findViewById(R.id.overflow_icons_view);
-        mIconsView.setMoreText((TextView) findViewById(R.id.more_text));
-        mIconsView.setOverflowIndicator(findViewById(R.id.more_icon_overflow));
-        mContent = findViewById(R.id.content);
-        mViewInvertHelper = new ViewInvertHelper(mContent,
-                NotificationPanelView.DOZE_ANIMATION_DURATION);
-    }
-
-    @Override
-    public void setDark(boolean dark, boolean fade, long delay) {
-        super.setDark(dark, fade, delay);
-        if (mDark == dark) return;
-        mDark = dark;
-        if (fade) {
-            mViewInvertHelper.fade(dark, delay);
-        } else {
-            mViewInvertHelper.update(dark);
-        }
-    }
-
-    @Override
-    protected View getContentView() {
-        return mContent;
-    }
-
-    public NotificationOverflowIconsView getIconsView() {
-        return mIconsView;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
deleted file mode 100644
index 88bb714..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar;
-
-import android.app.Notification;
-import android.content.Context;
-import android.graphics.PorterDuff;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.internal.util.NotificationColorUtil;
-import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.IconMerger;
-
-/**
- * A view to display all the overflowing icons on Keyguard.
- */
-public class NotificationOverflowIconsView extends IconMerger {
-
-    private TextView mMoreText;
-    private int mTintColor;
-    private int mIconSize;
-    private NotificationColorUtil mNotificationColorUtil;
-
-    public NotificationOverflowIconsView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mNotificationColorUtil = NotificationColorUtil.getInstance(getContext());
-        mTintColor = getContext().getColor(R.color.keyguard_overflow_content_color);
-        mIconSize = getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.status_bar_icon_size);
-    }
-
-    public void setMoreText(TextView moreText) {
-        mMoreText = moreText;
-    }
-
-    public void addNotification(NotificationData.Entry notification) {
-        StatusBarIconView v = new StatusBarIconView(getContext(), "",
-                notification.notification.getNotification());
-        v.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
-        addView(v, mIconSize, mIconSize);
-        v.set(notification.icon.getStatusBarIcon());
-        applyColor(notification.notification.getNotification(), v);
-        updateMoreText();
-    }
-
-    private void applyColor(Notification notification, StatusBarIconView view) {
-        view.setColorFilter(mTintColor, PorterDuff.Mode.MULTIPLY);
-    }
-
-    private void updateMoreText() {
-        mMoreText.setText(
-                getResources().getString(R.string.keyguard_more_overflow_text, getChildCount()));
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
new file mode 100644
index 0000000..680562a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -0,0 +1,474 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.content.Context;
+import android.content.res.Configuration;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.ViewInvertHelper;
+import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.phone.NotificationIconContainer;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
+import com.android.systemui.statusbar.stack.AmbientState;
+import com.android.systemui.statusbar.stack.AnimationProperties;
+import com.android.systemui.statusbar.stack.ExpandableViewState;
+import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.stack.StackScrollState;
+
+import java.util.ArrayList;
+import java.util.WeakHashMap;
+
+/**
+ * A notification shelf view that is placed inside the notification scroller. It manages the
+ * overflow icons that don't fit into the regular list anymore.
+ */
+public class NotificationShelf extends ActivatableNotificationView {
+
+    private ViewInvertHelper mViewInvertHelper;
+    private boolean mDark;
+    private NotificationIconContainer mShelfIcons;
+    private ArrayList<StatusBarIconView> mIcons = new ArrayList<>();
+    private ShelfState mShelfState;
+    private int[] mTmp = new int[2];
+    private boolean mHideBackground;
+    private int mIconAppearTopPadding;
+    private int mStatusBarHeight;
+    private int mStatusBarPaddingStart;
+    private AmbientState mAmbientState;
+    private NotificationStackScrollLayout mHostLayout;
+    private int mMaxLayoutHeight;
+    private int mPaddingBetweenElements;
+    private int mNotGoneIndex;
+    private boolean mHasItemsInStableShelf;
+    private NotificationIconContainer mCollapsedIcons;
+
+    public NotificationShelf(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mShelfIcons = (NotificationIconContainer) findViewById(R.id.content);
+        mShelfIcons.setClipChildren(false);
+        mShelfIcons.setClipToPadding(false);
+
+        setClipToActualHeight(false);
+        setClipChildren(false);
+        setClipToPadding(false);
+        mShelfIcons.setShowAllIcons(false);
+        mViewInvertHelper = new ViewInvertHelper(mShelfIcons,
+                NotificationPanelView.DOZE_ANIMATION_DURATION);
+        mShelfState = new ShelfState();
+        initDimens();
+    }
+
+    public void bind(AmbientState ambientState, NotificationStackScrollLayout hostLayout) {
+        mAmbientState = ambientState;
+        mHostLayout = hostLayout;
+    }
+
+    private void initDimens() {
+        mIconAppearTopPadding = getResources().getDimensionPixelSize(
+                R.dimen.notification_icon_appear_padding);
+        mStatusBarHeight = getResources().getDimensionPixelOffset(R.dimen.status_bar_height);
+        mStatusBarPaddingStart = getResources().getDimensionPixelOffset(
+                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
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        initDimens();
+    }
+
+    @Override
+    public void setDark(boolean dark, boolean fade, long delay) {
+        super.setDark(dark, fade, delay);
+        if (mDark == dark) return;
+        mDark = dark;
+        if (fade) {
+            mViewInvertHelper.fade(dark, delay);
+        } else {
+            mViewInvertHelper.update(dark);
+        }
+    }
+
+    @Override
+    protected View getContentView() {
+        return mShelfIcons;
+    }
+
+    public NotificationIconContainer getShelfIcons() {
+        return mShelfIcons;
+    }
+
+    @Override
+    public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
+        return mShelfState;
+    }
+
+    public void updateState(StackScrollState resultState,
+            AmbientState ambientState) {
+        View lastView = ambientState.getLastVisibleBackgroundChild();
+        if (lastView != null) {
+            float maxShelfEnd = ambientState.getInnerHeight() + ambientState.getTopPadding()
+                    + ambientState.getStackTranslation();
+            ExpandableViewState lastViewState = resultState.getViewStateForView(lastView);
+            float viewEnd = lastViewState.yTranslation + lastViewState.height;
+            mShelfState.copyFrom(lastViewState);
+            mShelfState.height = getIntrinsicHeight();
+            mShelfState.yTranslation = Math.max(Math.min(viewEnd, maxShelfEnd) - mShelfState.height,
+                    getFullyClosedTranslation());
+            mShelfState.zTranslation = ambientState.getBaseZHeight();
+            float openedAmount = (mShelfState.yTranslation - getFullyClosedTranslation())
+                    / (getIntrinsicHeight() * 2);
+            openedAmount = Math.min(1.0f, openedAmount);
+            mShelfState.openedAmount = openedAmount;
+            mShelfState.clipTopAmount = 0;
+            mShelfState.alpha = 1.0f;
+            mShelfState.belowSpeedBump = mAmbientState.getSpeedBumpIndex() == 0;
+            mShelfState.shadowAlpha = 1.0f;
+            mShelfState.hideSensitive = false;
+            mShelfState.xTranslation = getTranslationX();
+            if (mNotGoneIndex != -1) {
+                mShelfState.notGoneIndex = Math.min(mShelfState.notGoneIndex, mNotGoneIndex);
+            }
+            mShelfState.hasItemsInStableShelf = lastViewState.inShelf;
+        } else {
+            mShelfState.hidden = true;
+            mShelfState.location = ExpandableViewState.LOCATION_GONE;
+            mShelfState.hasItemsInStableShelf = false;
+        }
+    }
+
+    /**
+     * Update the shelf appearance based on the other notifications around it. This transforms
+     * the icons from the notification area into the shelf.
+     */
+    public void updateAppearance() {
+        WeakHashMap<View, NotificationIconContainer.IconState> iconStates =
+                mShelfIcons.resetViewStates();
+        float numViewsInShelf = 0.0f;
+        View lastChild = mAmbientState.getLastVisibleBackgroundChild();
+        mNotGoneIndex = -1;
+        float interpolationStart = mMaxLayoutHeight - getIntrinsicHeight() * 2;
+        float expandAmount = 0.0f;
+        if (getTranslationY() >= interpolationStart) {
+            expandAmount = (getTranslationY() - interpolationStart) / getIntrinsicHeight();
+            expandAmount = Math.min(1.0f, expandAmount);
+        }
+        //  find the first view that doesn't overlap with the shelf
+        int notificationIndex = 0;
+        int notGoneIndex = 0;
+        int colorOfViewBeforeLast = 0;
+        boolean backgroundForceHidden = false;
+        if (mHideBackground && !mShelfState.hasItemsInStableShelf) {
+            backgroundForceHidden = true;
+        }
+        int colorTwoBefore = NO_COLOR;
+        int previousColor = NO_COLOR;
+        float transitionAmount = 0.0f;
+        while (notificationIndex < mHostLayout.getChildCount()) {
+            ExpandableView child = (ExpandableView) mHostLayout.getChildAt(notificationIndex);
+            notificationIndex++;
+            if (!(child instanceof ExpandableNotificationRow)
+                    || child.getVisibility() == GONE) {
+                continue;
+            }
+            ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+            StatusBarIconView icon = row.getEntry().expandedIcon;
+            NotificationIconContainer.IconState iconState = iconStates.get(icon);
+            float notificationClipEnd;
+            float shelfStart = getTranslationY();
+            boolean aboveShelf = row.getTranslationZ() > mAmbientState.getBaseZHeight();
+            boolean isLastChild = child == lastChild;
+            if (isLastChild || aboveShelf || backgroundForceHidden) {
+                notificationClipEnd = shelfStart + getIntrinsicHeight();
+            } else {
+                notificationClipEnd = shelfStart - mPaddingBetweenElements;
+                float height = notificationClipEnd - row.getTranslationY();
+                if (!row.isBelowSpeedBump() && height <= getNotificationMergeSize()) {
+                    // We want the gap to close when we reached the minimum size and only shrink
+                    // before
+                    notificationClipEnd = Math.min(shelfStart,
+                            row.getTranslationY() + getNotificationMergeSize());
+                }
+            }
+            updateNotificationClipHeight(row, notificationClipEnd);
+            float inShelfAmount = updateIconAppearance(row, iconState, icon, expandAmount,
+                    isLastChild);
+            numViewsInShelf += inShelfAmount;
+            int ownColorUntinted = row.getBackgroundColorWithoutTint();
+            if (row.getTranslationY() >= getTranslationY() && mNotGoneIndex == -1) {
+                mNotGoneIndex = notGoneIndex;
+                setTintColor(previousColor);
+                setOverrideTintColor(colorTwoBefore, transitionAmount);
+
+            } else if (mNotGoneIndex == -1) {
+                colorTwoBefore = previousColor;
+                transitionAmount = inShelfAmount;
+            }
+            if (isLastChild && colorOfViewBeforeLast != NO_COLOR) {
+                row.setOverrideTintColor(colorOfViewBeforeLast, inShelfAmount);
+            } else {
+                colorOfViewBeforeLast = ownColorUntinted;
+                row.setOverrideTintColor(NO_COLOR, 0 /* overrideAmount */);
+            }
+            if (notGoneIndex != 0 || !aboveShelf) {
+                row.setAboveShelf(false);
+            }
+            notGoneIndex++;
+            previousColor = ownColorUntinted;
+        }
+        mShelfIcons.calculateIconTranslations();
+        mShelfIcons.applyIconStates();
+        setVisibility(numViewsInShelf != 0.0f && mAmbientState.isShadeExpanded()
+                ? VISIBLE
+                : INVISIBLE);
+        boolean hideBackground = numViewsInShelf < 1.0f;
+        setHideBackground(hideBackground || backgroundForceHidden);
+        if (mNotGoneIndex == -1) {
+            mNotGoneIndex = notGoneIndex;
+        }
+    }
+
+    private void updateNotificationClipHeight(ExpandableNotificationRow row,
+            float notificationClipEnd) {
+        float viewEnd = row.getTranslationY() + row.getActualHeight();
+        if (viewEnd > notificationClipEnd
+                && (mAmbientState.isShadeExpanded()
+                        || (!row.isPinned() && !row.isHeadsUpAnimatingAway()))) {
+            row.setClipBottomAmount((int) (viewEnd - notificationClipEnd));
+        } else {
+            row.setClipBottomAmount(0);
+        }
+    }
+
+    /**
+     * @return the icon amount how much this notification is in the shelf;
+     */
+    private float updateIconAppearance(ExpandableNotificationRow row,
+            NotificationIconContainer.IconState iconState, StatusBarIconView icon,
+            float expandAmount, boolean isLastChild) {
+        // Let calculate how much the view is in the shelf
+        float viewStart = row.getTranslationY();
+        int transformHeight = row.getActualHeight() + mPaddingBetweenElements;
+        if (isLastChild) {
+            transformHeight =
+                    Math.min(transformHeight, row.getMinHeight() - getIntrinsicHeight());
+        }
+        float viewEnd = viewStart + transformHeight;
+        float iconAppearAmount;
+        float yTranslation;
+        float alpha = 1.0f;
+        if (viewEnd >= getTranslationY() && (mAmbientState.isShadeExpanded()
+                || (!row.isPinned() && !row.isHeadsUpAnimatingAway()))) {
+            if (viewStart < getTranslationY()) {
+                float linearAmount = (getTranslationY() - viewStart) / transformHeight;
+                float interpolatedAmount =  Interpolators.ACCELERATE_DECELERATE.getInterpolation(
+                        linearAmount);
+                interpolatedAmount = NotificationUtils.interpolate(
+                        interpolatedAmount, linearAmount, expandAmount);
+                iconAppearAmount = 1.0f - interpolatedAmount;
+            } else {
+                iconAppearAmount = 1.0f;
+            }
+        } else {
+            iconAppearAmount = 0.0f;
+        }
+
+        // Lets now calculate how much of the transformation has already happened. This is different
+        // from the above, since we only start transforming when the view is already quite a bit
+        // pushed in.
+        View rowIcon = row.getNotificationIcon();
+        float notificationIconPosition = viewStart;
+        float notificationIconSize = 0.0f;
+        int iconTopPadding;
+        if (rowIcon != null) {
+            iconTopPadding = row.getRelativeTopPadding(rowIcon);
+            notificationIconSize = rowIcon.getHeight();
+        } else {
+            iconTopPadding = mIconAppearTopPadding;
+        }
+        notificationIconPosition += iconTopPadding;
+        float shelfIconPosition = getTranslationY() + icon.getTop();
+        shelfIconPosition += ((1.0f - icon.getIconScale()) * icon.getHeight()) / 2.0f;
+        float transitionDistance = getIntrinsicHeight() * 1.5f;
+        if (isLastChild) {
+            transitionDistance = Math.min(transitionDistance, row.getMinHeight()
+                    - getIntrinsicHeight());
+        }
+        float transformationStartPosition = getTranslationY() - transitionDistance;
+        float transitionAmount = 0.0f;
+        if (viewStart < transformationStartPosition
+                || (!mAmbientState.isShadeExpanded()
+                        && (row.isPinned() || row.isHeadsUpAnimatingAway()))) {
+            // We simply place it on the icon of the notification
+            yTranslation = notificationIconPosition - shelfIconPosition;
+        } else {
+            transitionAmount = (viewStart - transformationStartPosition)
+                    / transitionDistance;
+            float startPosition = transformationStartPosition + iconTopPadding;
+            yTranslation = NotificationUtils.interpolate(
+                    startPosition - shelfIconPosition, 0, transitionAmount);
+            // If we are merging into the shelf, lets make sure the shelf is at least on our height,
+            // otherwise the icons won't be visible.
+            setTranslationZ(Math.max(getTranslationZ(), row.getTranslationZ()));
+        }
+        float shelfIconSize = icon.getHeight() * icon.getIconScale();
+        if (!row.isShowingIcon()) {
+            // The view currently doesn't have an icon, lets transform it in!
+            alpha = transitionAmount;
+            notificationIconSize = shelfIconSize / 2.0f;
+        }
+        // The notification size is different from the size in the shelf / statusbar
+        float newSize = NotificationUtils.interpolate(notificationIconSize, shelfIconSize,
+                transitionAmount);
+        row.setIconTransformationAmount(transitionAmount, isLastChild);
+        if (iconState != null) {
+            iconState.scaleX = newSize / icon.getHeight() / icon.getIconScale();
+            iconState.scaleY = iconState.scaleX;
+            iconState.hidden = transitionAmount == 0.0f;
+            iconState.iconAppearAmount = iconAppearAmount;
+            iconState.alpha = alpha;
+            iconState.yTranslation = yTranslation;
+            icon.setVisibility(transitionAmount == 0.0f ? INVISIBLE : VISIBLE);
+            if (row.isInShelf() && !row.isTransformingIntoShelf()) {
+                iconState.iconAppearAmount = 1.0f;
+                iconState.alpha = 1.0f;
+                iconState.scaleX = 1.0f;
+                iconState.scaleY = 1.0f;
+                iconState.hidden = false;
+            }
+        }
+        return iconAppearAmount;
+    }
+
+    private float getFullyClosedTranslation() {
+        return - (getIntrinsicHeight() - mStatusBarHeight) / 2;
+    }
+
+    public int getNotificationMergeSize() {
+        return getIntrinsicHeight();
+    }
+
+    @Override
+    public boolean hasNoContentHeight() {
+        return true;
+    }
+
+    private void setHideBackground(boolean hideBackground) {
+        mHideBackground = hideBackground;
+        updateBackground();
+        updateOutline();
+    }
+
+    public boolean hidesBackground() {
+        return mHideBackground;
+    }
+
+    @Override
+    protected boolean needsOutline() {
+        return !mHideBackground && super.needsOutline();
+    }
+
+    @Override
+    protected boolean shouldHideBackground() {
+        return super.shouldHideBackground() || mHideBackground;
+    }
+
+    private void setOpenedAmount(float openedAmount) {
+        mCollapsedIcons.getLocationOnScreen(mTmp);
+        int start = mTmp[0];
+        if (isLayoutRtl()) {
+            start = getWidth() - start - mCollapsedIcons.getWidth();
+        }
+        int width = (int) NotificationUtils.interpolate(start + mCollapsedIcons.getWidth(),
+                mShelfIcons.getWidth(),
+                openedAmount);
+        mShelfIcons.setActualLayoutWidth(width);
+        float padding = NotificationUtils.interpolate(mCollapsedIcons.getPaddingEnd(),
+                mShelfIcons.getPaddingEnd(),
+                openedAmount);
+        mShelfIcons.setActualPaddingEnd(padding);
+        float paddingStart = NotificationUtils.interpolate(start,
+                mShelfIcons.getPaddingStart(), openedAmount);
+        mShelfIcons.setActualPaddingStart(paddingStart);
+    }
+
+    public void setMaxLayoutHeight(int maxLayoutHeight) {
+        mMaxLayoutHeight = maxLayoutHeight;
+    }
+
+    /**
+     * @return the index of the notification at which the shelf visually resides
+     */
+    public int getNotGoneIndex() {
+        return mNotGoneIndex;
+    }
+
+    private void setHasItemsInStableShelf(boolean hasItemsInStableShelf) {
+        mHasItemsInStableShelf = hasItemsInStableShelf;
+    }
+
+    /**
+     * @return whether the shelf has any icons in it when a potential animation has finished, i.e
+     *         if the current state would be applied right now
+     */
+    public boolean hasItemsInStableShelf() {
+        return mHasItemsInStableShelf;
+    }
+
+    public void setCollapsedIcons(NotificationIconContainer collapsedIcons) {
+        mCollapsedIcons = collapsedIcons;
+    }
+
+    private class ShelfState extends ExpandableViewState {
+        private float openedAmount;
+        private boolean hasItemsInStableShelf;
+
+        @Override
+        public void applyToView(View view) {
+            super.applyToView(view);
+            updateAppearance();
+            setOpenedAmount(openedAmount);
+            setHasItemsInStableShelf(hasItemsInStableShelf);
+        }
+
+        @Override
+        public void animateTo(View child, AnimationProperties properties) {
+            super.animateTo(child, properties);
+            setOpenedAmount(openedAmount);
+            updateAppearance();
+            setHasItemsInStableShelf(hasItemsInStableShelf);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index cdfdad4..d635bb0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.statusbar;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
 import android.app.Notification;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -30,20 +33,55 @@
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.util.FloatProperty;
 import android.util.Log;
+import android.util.Property;
 import android.util.TypedValue;
 import android.view.ViewDebug;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.Interpolator;
 
 import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.NotificationUtils;
 
 import java.text.NumberFormat;
 
 public class StatusBarIconView extends AnimatedImageView {
-    private static final String TAG = "StatusBarIconView";
-    private boolean mAlwaysScaleIcon;
+    public static final int STATE_ICON = 0;
+    public static final int STATE_DOT = 1;
+    public static final int STATE_HIDDEN = 2;
 
+    private static final String TAG = "StatusBarIconView";
+    private static final Property<StatusBarIconView, Float> ICON_APPEAR_AMOUNT
+            = new FloatProperty<StatusBarIconView>("iconAppearAmount") {
+
+        @Override
+        public void setValue(StatusBarIconView object, float value) {
+            object.setIconAppearAmount(value);
+        }
+
+        @Override
+        public Float get(StatusBarIconView object) {
+            return object.getIconAppearAmount();
+        }
+    };
+    private static final Property<StatusBarIconView, Float> DOT_APPEAR_AMOUNT
+            = new FloatProperty<StatusBarIconView>("dot_appear_amount") {
+
+        @Override
+        public void setValue(StatusBarIconView object, float value) {
+            object.setDotAppearAmount(value);
+        }
+
+        @Override
+        public Float get(StatusBarIconView object) {
+            return object.getDotAppearAmount();
+        }
+    };
+
+    private boolean mAlwaysScaleIcon;
     private StatusBarIcon mIcon;
     @ViewDebug.ExportedProperty private String mSlot;
     private Drawable mNumberBackground;
@@ -54,6 +92,16 @@
     private Notification mNotification;
     private final boolean mBlocked;
     private int mDensity;
+    private float mIconScale = 1.0f;
+    private final Paint mDotPaint = new Paint();
+    private boolean mDotVisible;
+    private float mDotRadius;
+    private int mStaticDotRadius;
+    private int mVisibleState = STATE_ICON;
+    private float mIconAppearAmount = 1.0f;
+    private ObjectAnimator mIconAppearAnimator;
+    private ObjectAnimator mDotAnimator;
+    private float mDotAppearAmount;
 
     public StatusBarIconView(Context context, String slot, Notification notification) {
         this(context, slot, notification, false);
@@ -72,6 +120,11 @@
         maybeUpdateIconScale();
         setScaleType(ScaleType.CENTER);
         mDensity = context.getResources().getDisplayMetrics().densityDpi;
+        if (mNotification != null) {
+            setIconTint(getContext().getColor(
+                    com.android.internal.R.color.notification_icon_default_color));
+        }
+        reloadDimens();
     }
 
     private void maybeUpdateIconScale() {
@@ -86,9 +139,11 @@
         Resources res = mContext.getResources();
         final int outerBounds = res.getDimensionPixelSize(R.dimen.status_bar_icon_size);
         final int imageBounds = res.getDimensionPixelSize(R.dimen.status_bar_icon_drawing_size);
-        final float scale = (float)imageBounds / (float)outerBounds;
-        setScaleX(scale);
-        setScaleY(scale);
+        mIconScale = (float)imageBounds / (float)outerBounds;
+    }
+
+    public float getIconScale() {
+        return mIconScale;
     }
 
     @Override
@@ -99,6 +154,15 @@
             mDensity = density;
             maybeUpdateIconScale();
             updateDrawable();
+            reloadDimens();
+        }
+    }
+
+    private void reloadDimens() {
+        boolean applyRadius = mDotRadius == mStaticDotRadius;
+        mStaticDotRadius = getResources().getDimensionPixelSize(R.dimen.overflow_dot_radius);
+        if (applyRadius) {
+            mDotRadius = mStaticDotRadius;
         }
     }
 
@@ -259,12 +323,32 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
+        if (mIconAppearAmount > 0.0f) {
+            canvas.save();
+            canvas.scale(mIconScale * mIconAppearAmount, mIconScale * mIconAppearAmount,
+                    getWidth() / 2, getHeight() / 2);
+            super.onDraw(canvas);
+            canvas.restore();
+        }
 
         if (mNumberBackground != null) {
             mNumberBackground.draw(canvas);
             canvas.drawText(mNumberText, mNumberX, mNumberY, mNumberPain);
         }
+        if (mDotAppearAmount != 0.0f) {
+            float radius;
+            float alpha;
+            if (mDotAppearAmount <= 1.0f) {
+                radius = mDotRadius * mDotAppearAmount;
+                alpha = 1.0f;
+            } else {
+                float fadeOutAmount = mDotAppearAmount - 1.0f;
+                alpha = 1.0f - fadeOutAmount;
+                radius = NotificationUtils.interpolate(mDotRadius, getWidth() / 4, fadeOutAmount);
+            }
+            mDotPaint.setAlpha((int) (alpha * 255));
+            canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius, mDotPaint);
+        }
     }
 
     @Override
@@ -351,4 +435,97 @@
         return c.getString(R.string.accessibility_desc_notification_icon, appName, desc);
     }
 
+    public void setIconTint(int iconTint) {
+        mDotPaint.setColor(iconTint);
+    }
+
+    public void setVisibleState(int state) {
+        setVisibleState(state, true /* animate */, null /* endRunnable */);
+    }
+
+    public void setVisibleState(int state, boolean animate) {
+        setVisibleState(state, animate, null);
+    }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+
+    public void setVisibleState(int visibleState, boolean animate, Runnable endRunnable) {
+        if (visibleState != mVisibleState) {
+            mVisibleState = visibleState;
+            if (animate) {
+                if (mIconAppearAnimator != null) {
+                    mIconAppearAnimator.cancel();
+                }
+                float targetAmount = 0.0f;
+                Interpolator interpolator = Interpolators.FAST_OUT_LINEAR_IN;
+                if (visibleState == STATE_ICON) {
+                    targetAmount = 1.0f;
+                    interpolator = Interpolators.LINEAR_OUT_SLOW_IN;
+                }
+                mIconAppearAnimator = ObjectAnimator.ofFloat(this, ICON_APPEAR_AMOUNT,
+                        targetAmount);
+                mIconAppearAnimator.setInterpolator(interpolator);
+                mIconAppearAnimator.setDuration(100);
+                mIconAppearAnimator.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        mIconAppearAnimator = null;
+                        if (endRunnable != null) {
+                            endRunnable.run();
+                        }
+                    }
+                });
+                mIconAppearAnimator.start();
+
+                if (mDotAnimator != null) {
+                    mDotAnimator.cancel();
+                }
+                targetAmount = visibleState == STATE_ICON ? 2.0f : 0.0f;
+                interpolator = Interpolators.FAST_OUT_LINEAR_IN;
+                if (visibleState == STATE_DOT) {
+                    targetAmount = 1.0f;
+                    interpolator = Interpolators.LINEAR_OUT_SLOW_IN;
+                }
+                mDotAnimator = ObjectAnimator.ofFloat(this, DOT_APPEAR_AMOUNT,
+                        targetAmount);
+                mDotAnimator.setInterpolator(interpolator);
+                mDotAnimator.setDuration(100);
+                mDotAnimator.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        mDotAnimator = null;
+                    }
+                });
+                mDotAnimator.start();
+            } else {
+                setIconAppearAmount(visibleState == STATE_ICON ? 1.0f : 0.0f);
+                setDotAppearAmount(visibleState == STATE_DOT ? 1.0f : 0.0f);
+            }
+        }
+    }
+
+    public void setIconAppearAmount(float iconAppearAmount) {
+        mIconAppearAmount = iconAppearAmount;
+        invalidate();
+    }
+
+    public float getIconAppearAmount() {
+        return mIconAppearAmount;
+    }
+
+    public int getVisibleState() {
+        return mVisibleState;
+    }
+
+    public void setDotAppearAmount(float dotAppearAmount) {
+        mDotAppearAmount = dotAppearAmount;
+        invalidate();
+    }
+
+    public float getDotAppearAmount() {
+        return mDotAppearAmount;
+    }
 }
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/IconMerger.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
deleted file mode 100644
index f86badb..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.LinearLayout;
-
-import com.android.systemui.R;
-
-public class IconMerger extends LinearLayout {
-    private static final String TAG = "IconMerger";
-    private static final boolean DEBUG = false;
-
-    private int mIconSize;
-    private int mIconHPadding;
-
-    private View mMoreView;
-
-    public IconMerger(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        reloadDimens();
-        if (DEBUG) {
-            setBackgroundColor(0x800099FF);
-        }
-    }
-
-    private void reloadDimens() {
-        Resources res = mContext.getResources();
-        mIconSize = res.getDimensionPixelSize(R.dimen.status_bar_icon_size);
-        mIconHPadding = res.getDimensionPixelSize(R.dimen.status_bar_icon_padding);
-    }
-
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        reloadDimens();
-    }
-
-    public void setOverflowIndicator(View v) {
-        mMoreView = v;
-    }
-
-    private int getFullIconWidth() {
-        return mIconSize + 2 * mIconHPadding;
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        // we need to constrain this to an integral multiple of our children
-        int width = getMeasuredWidth();
-        setMeasuredDimension(width - (width % getFullIconWidth()), getMeasuredHeight());
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        super.onLayout(changed, l, t, r, b);
-        checkOverflow(r - l);
-    }
-
-    private void checkOverflow(int width) {
-        if (mMoreView == null) return;
-
-        final int N = getChildCount();
-        int visibleChildren = 0;
-        for (int i=0; i<N; i++) {
-            if (getChildAt(i).getVisibility() != GONE) visibleChildren++;
-        }
-        final boolean overflowShown = (mMoreView.getVisibility() == View.VISIBLE);
-        // let's assume we have one more slot if the more icon is already showing
-        if (overflowShown) visibleChildren --;
-        final boolean moreRequired = visibleChildren * getFullIconWidth() > width;
-        if (moreRequired != overflowShown) {
-            post(new Runnable() {
-                @Override
-                public void run() {
-                    mMoreView.setVisibility(moreRequired ? View.VISIBLE : View.GONE);
-                }
-            });
-        }
-    }
-}
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/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 34b8371..2124011 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -37,6 +37,7 @@
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.keyguard.DismissCallbackRegistry;
 
 import static com.android.keyguard.KeyguardHostView.OnDismissAction;
 import static com.android.keyguard.KeyguardSecurityModel.SecurityMode;
@@ -48,17 +49,17 @@
 
     final static private String TAG = "KeyguardBouncer";
 
-    protected Context mContext;
-    protected ViewMediatorCallback mCallback;
-    protected LockPatternUtils mLockPatternUtils;
-    protected ViewGroup mContainer;
-    private StatusBarWindowManager mWindowManager;
+    protected final Context mContext;
+    protected final ViewMediatorCallback mCallback;
+    protected final LockPatternUtils mLockPatternUtils;
+    protected final ViewGroup mContainer;
+    private final FalsingManager mFalsingManager;
+    private final DismissCallbackRegistry mDismissCallbackRegistry;
     protected KeyguardHostView mKeyguardView;
     protected ViewGroup mRoot;
     private boolean mShowingSoon;
     private int mBouncerPromptReason;
-    private FalsingManager mFalsingManager;
-    private KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
+    private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
             new KeyguardUpdateMonitorCallback() {
                 @Override
                 public void onStrongAuthStateChanged(int userId) {
@@ -67,15 +68,15 @@
             };
 
     public KeyguardBouncer(Context context, ViewMediatorCallback callback,
-            LockPatternUtils lockPatternUtils, StatusBarWindowManager windowManager,
-            ViewGroup container) {
+            LockPatternUtils lockPatternUtils, ViewGroup container,
+            DismissCallbackRegistry dismissCallbackRegistry) {
         mContext = context;
         mCallback = callback;
         mLockPatternUtils = lockPatternUtils;
         mContainer = container;
-        mWindowManager = windowManager;
         KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback);
         mFalsingManager = FalsingManager.getInstance(mContext);
+        mDismissCallbackRegistry = dismissCallbackRegistry;
     }
 
     public void show(boolean resetSecuritySelection) {
@@ -169,6 +170,9 @@
     }
 
     public void hide(boolean destroyView) {
+        if (isShowing()) {
+            mDismissCallbackRegistry.notifyDismissCancelled();
+        }
         mFalsingManager.onBouncerHidden();
         cancelShowRunnable();
         if (mKeyguardView != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 784cb48..70beac8ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -80,7 +80,7 @@
         mClockYFractionMin = res.getFraction(R.fraction.keyguard_clock_y_fraction_min, 1, 1);
         mClockYFractionMax = res.getFraction(R.fraction.keyguard_clock_y_fraction_max, 1, 1);
         mMoreCardNotificationAmount =
-                (float) res.getDimensionPixelSize(R.dimen.notification_summary_height) /
+                (float) res.getDimensionPixelSize(R.dimen.notification_shelf_height) /
                         res.getDimensionPixelSize(R.dimen.notification_min_height);
         mDensity = res.getDisplayMetrics().density;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 9bb4936..695b500 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -35,6 +35,8 @@
  */
 public class LockIcon extends KeyguardAffordanceView {
 
+    private static final int FP_DRAW_OFF_TIMEOUT = 800;
+
     private static final int STATE_LOCKED = 0;
     private static final int STATE_LOCK_OPEN = 1;
     private static final int STATE_FACE_UNLOCK = 2;
@@ -53,6 +55,8 @@
     private boolean mHasFingerPrintIcon;
     private int mDensity;
 
+    private final Runnable mDrawOffTimeout = () -> update(true /* forceUpdate */);
+
     public LockIcon(Context context, AttributeSet attrs) {
         super(context, attrs);
         mTrustDrawable = new TrustDrawable(context);
@@ -116,7 +120,6 @@
         } else {
             mTrustDrawable.stop();
         }
-        // TODO: Real icon for facelock.
         int state = getState();
         boolean anyFingerprintIcon = state == STATE_FINGERPRINT || state == STATE_FINGERPRINT_ERROR;
         boolean useAdditionalPadding = anyFingerprintIcon;
@@ -171,6 +174,14 @@
                 animation.forceAnimationOnUI();
                 animation.start();
             }
+
+            if (iconRes == R.drawable.lockscreen_fingerprint_draw_off_animation) {
+                removeCallbacks(mDrawOffTimeout);
+                postDelayed(mDrawOffTimeout, FP_DRAW_OFF_TIMEOUT);
+            } else {
+                removeCallbacks(mDrawOffTimeout);
+            }
+
             mLastState = state;
             mLastDeviceInteractive = mDeviceInteractive;
             mLastScreenOn = mScreenOn;
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 cbaab14..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,16 +8,19 @@
 import android.support.annotation.NonNull;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
+import android.widget.FrameLayout;
 
 import com.android.internal.util.NotificationColorUtil;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 import java.util.ArrayList;
+import java.util.function.Function;
 
 /**
  * A controller for the space in the status bar to the left of the system icons. This area is
@@ -32,13 +35,16 @@
 
     private PhoneStatusBar mPhoneStatusBar;
     protected View mNotificationIconArea;
-    private IconMerger mNotificationIcons;
-    private ImageView mMoreIcon;
+    private NotificationIconContainer mNotificationIcons;
+    private NotificationIconContainer mShelfIcons;
     private final Rect mTintArea = new Rect();
+    private NotificationStackScrollLayout mNotificationScrollLayout;
+    private Context mContext;
 
     public NotificationIconAreaController(Context context, PhoneStatusBar phoneStatusBar) {
         mPhoneStatusBar = phoneStatusBar;
         mNotificationColorUtil = NotificationColorUtil.getInstance(context);
+        mContext = context;
 
         initializeNotificationAreaViews(context);
     }
@@ -55,29 +61,30 @@
 
         LayoutInflater layoutInflater = LayoutInflater.from(context);
         mNotificationIconArea = inflateIconArea(layoutInflater);
+        mNotificationIcons = (NotificationIconContainer) mNotificationIconArea.findViewById(
+                R.id.notificationIcons);
 
-        mNotificationIcons =
-                (IconMerger) mNotificationIconArea.findViewById(R.id.notificationIcons);
+        NotificationShelf shelf = mPhoneStatusBar.getNotificationShelf();
+        mShelfIcons = shelf.getShelfIcons();
+        shelf.setCollapsedIcons(mNotificationIcons);
 
-        mMoreIcon = (ImageView) mNotificationIconArea.findViewById(R.id.moreIcon);
-        if (mMoreIcon != null) {
-            mMoreIcon.setImageTintList(ColorStateList.valueOf(mIconTint));
-            mNotificationIcons.setOverflowIndicator(mMoreIcon);
-        }
+        mNotificationScrollLayout = mPhoneStatusBar.getNotificationScrollLayout();
     }
 
     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());
     }
 
@@ -109,14 +116,10 @@
     }
 
     /**
-     * Sets the color that should be used to tint any icons in the notification area. If this
-     * method is not called, the default tint is {@link Color#WHITE}.
+     * Sets the color that should be used to tint any icons in the notification area.
      */
     public void setIconTint(int iconTint) {
         mIconTint = iconTint;
-        if (mMoreIcon != null) {
-            mMoreIcon.setImageTintList(ColorStateList.valueOf(mIconTint));
-        }
         applyNotificationIconsTint();
     }
 
@@ -144,24 +147,54 @@
      * Updates the notifications with the given list of notifications to display.
      */
     public void updateNotificationIcons(NotificationData notificationData) {
-        final LinearLayout.LayoutParams params = generateIconLayoutParams();
 
-        ArrayList<NotificationData.Entry> activeNotifications =
-                notificationData.getActiveNotifications();
-        final int size = activeNotifications.size();
-        ArrayList<StatusBarIconView> toShow = new ArrayList<>(size);
+        updateIconsForLayout(notificationData, entry -> entry.icon, mNotificationIcons);
+        updateIconsForLayout(notificationData, entry -> entry.expandedIcon, mShelfIcons);
+
+        applyNotificationIconsTint();
+        ArrayList<NotificationData.Entry> activeNotifications
+                = notificationData.getActiveNotifications();
+        for (int i = 0; i < activeNotifications.size(); i++) {
+            NotificationData.Entry entry = activeNotifications.get(i);
+            boolean isPreL = Boolean.TRUE.equals(entry.expandedIcon.getTag(R.id.icon_is_pre_L));
+            boolean colorize = !isPreL
+                    || NotificationUtils.isGrayscale(entry.expandedIcon, mNotificationColorUtil);
+            if (colorize) {
+                int color = entry.getContrastedColor(mContext);
+                entry.expandedIcon.setImageTintList(ColorStateList.valueOf(color));
+            }
+        }
+    }
+
+    /**
+     * Updates the notification icons for a host layout. This will ensure that the notification
+     * host layout will have the same icons like the ones in here.
+     *
+     * @param notificationData the notification data to look up which notifications are relevant
+     * @param function A function to look up an icon view based on an entry
+     * @param hostLayout which layout should be updated
+     */
+    private void updateIconsForLayout(NotificationData notificationData,
+            Function<NotificationData.Entry, StatusBarIconView> function,
+            NotificationIconContainer hostLayout) {
+        ArrayList<StatusBarIconView> toShow = new ArrayList<>(
+                mNotificationScrollLayout.getChildCount());
 
         // Filter out ambient notifications and notification children.
-        for (int i = 0; i < size; i++) {
-            NotificationData.Entry ent = activeNotifications.get(i);
-            if (shouldShowNotification(ent, notificationData)) {
-                toShow.add(ent.icon);
+        for (int i = 0; i < mNotificationScrollLayout.getChildCount(); i++) {
+            View view = mNotificationScrollLayout.getChildAt(i);
+            if (view instanceof ExpandableNotificationRow) {
+                NotificationData.Entry ent = ((ExpandableNotificationRow) view).getEntry();
+                if (shouldShowNotification(ent, notificationData)) {
+                    toShow.add(function.apply(ent));
+                }
             }
         }
 
+
         ArrayList<View> toRemove = new ArrayList<>();
-        for (int i = 0; i < mNotificationIcons.getChildCount(); i++) {
-            View child = mNotificationIcons.getChildAt(i);
+        for (int i = 0; i < hostLayout.getChildCount(); i++) {
+            View child = hostLayout.getChildAt(i);
             if (!toShow.contains(child)) {
                 toRemove.add(child);
             }
@@ -169,29 +202,32 @@
 
         final int toRemoveCount = toRemove.size();
         for (int i = 0; i < toRemoveCount; i++) {
-            mNotificationIcons.removeView(toRemove.get(i));
+            hostLayout.removeView(toRemove.get(i));
         }
 
+        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
+            hostLayout.removeTransientView(v);
             if (v.getParent() == null) {
-                mNotificationIcons.addView(v, i, params);
+                hostLayout.addView(v, i, params);
             }
         }
 
+        hostLayout.setChangingViewPositions(true);
         // Re-sort notification icons
-        final int childCount = mNotificationIcons.getChildCount();
+        final int childCount = hostLayout.getChildCount();
         for (int i = 0; i < childCount; i++) {
-            View actual = mNotificationIcons.getChildAt(i);
+            View actual = hostLayout.getChildAt(i);
             StatusBarIconView expected = toShow.get(i);
             if (actual == expected) {
                 continue;
             }
-            mNotificationIcons.removeView(expected);
-            mNotificationIcons.addView(expected, i);
+            hostLayout.removeView(expected);
+            hostLayout.addView(expected, i);
         }
-
-        applyNotificationIconsTint();
+        hostLayout.setChangingViewPositions(false);
     }
 
     /**
@@ -206,6 +242,7 @@
                 v.setImageTintList(ColorStateList.valueOf(
                         StatusBarIconController.getTint(mTintArea, v, mIconTint)));
             }
+            v.setIconTint(mIconTint);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
new file mode 100644
index 0000000..03697b8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.AlphaOptimizedFrameLayout;
+import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.stack.AnimationFilter;
+import com.android.systemui.statusbar.stack.AnimationProperties;
+import com.android.systemui.statusbar.stack.ViewState;
+
+import java.util.WeakHashMap;
+
+/**
+ * A container for notification icons. It handles overflowing icons properly and positions them
+ * correctly on the screen.
+ */
+public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
+    private static final String TAG = "NotificationIconContainer";
+    private static final boolean DEBUG = false;
+    private static final AnimationProperties DOT_ANIMATION_PROPERTIES = new AnimationProperties() {
+        private AnimationFilter mAnimationFilter = new AnimationFilter().animateX();
+
+        @Override
+        public AnimationFilter getAnimationFilter() {
+            return mAnimationFilter;
+        }
+    }.setDuration(200);
+
+    private static final AnimationProperties ADD_ICON_PROPERTIES = new AnimationProperties() {
+        private AnimationFilter mAnimationFilter = new AnimationFilter().animateAlpha();
+
+        @Override
+        public AnimationFilter getAnimationFilter() {
+            return mAnimationFilter;
+        }
+    }.setDuration(200).setDelay(50);
+
+    private boolean mShowAllIcons = true;
+    private WeakHashMap<View, IconState> mIconStates = new WeakHashMap<>();
+    private int mDotPadding;
+    private int mStaticDotRadius;
+    private int mActualLayoutWidth = -1;
+    private float mActualPaddingEnd = -1;
+    private float mActualPaddingStart = -1;
+    private boolean mChangingViewPositions;
+    private int mAnimationStartIndex = -1;
+
+    public NotificationIconContainer(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        initDimens();
+        setWillNotDraw(!DEBUG);
+    }
+
+    private void initDimens() {
+        mDotPadding = getResources().getDimensionPixelSize(R.dimen.overflow_icon_dot_padding);
+        mStaticDotRadius = getResources().getDimensionPixelSize(R.dimen.overflow_dot_radius);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        Paint paint = new Paint();
+        paint.setColor(Color.RED);
+        paint.setStyle(Paint.Style.STROKE);
+        canvas.drawRect(getActualPaddingStart(), 0, getLayoutEnd(), getHeight(), paint);
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        initDimens();
+    }
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        float centerY = getHeight() / 2.0f;
+        // we layout all our children on the left at the top
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+            // We need to layout all children even the GONE ones, such that the heights are
+            // calculated correctly as they are used to calculate how many we can fit on the screen
+            int width = child.getMeasuredWidth();
+            int height = child.getMeasuredHeight();
+            int top = (int) (centerY - height / 2.0f);
+            child.layout(0, top, width, top + height);
+        }
+        if (mShowAllIcons) {
+            resetViewStates();
+            calculateIconTranslations();
+            applyIconStates();
+        }
+    }
+
+    public void applyIconStates() {
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+            ViewState childState = mIconStates.get(child);
+            if (childState != null) {
+                childState.applyToView(child);
+            }
+        }
+        mAnimationStartIndex = -1;
+    }
+
+    @Override
+    public void onViewAdded(View child) {
+        super.onViewAdded(child);
+        if (!mChangingViewPositions) {
+            mIconStates.put(child, new IconState());
+        }
+        int childIndex = indexOfChild(child);
+        if (childIndex < getChildCount() - 1
+            && mIconStates.get(getChildAt(childIndex + 1)).iconAppearAmount > 0.0f) {
+            if (mAnimationStartIndex < 0) {
+                mAnimationStartIndex = childIndex;
+            } else {
+                mAnimationStartIndex = Math.min(mAnimationStartIndex, childIndex);
+            }
+        }
+    }
+
+    @Override
+    public void onViewRemoved(View child) {
+        super.onViewRemoved(child);
+        if (child instanceof StatusBarIconView) {
+            final StatusBarIconView icon = (StatusBarIconView) child;
+            if (icon.getVisibleState() != StatusBarIconView.STATE_HIDDEN
+                    && child.getVisibility() == VISIBLE) {
+                int animationStartIndex = findFirstViewIndexAfter(icon.getTranslationX());
+                if (mAnimationStartIndex < 0) {
+                    mAnimationStartIndex = animationStartIndex;
+                } else {
+                    mAnimationStartIndex = Math.min(mAnimationStartIndex, animationStartIndex);
+                }
+            }
+            if (!mChangingViewPositions) {
+                mIconStates.remove(child);
+                addTransientView(icon, 0);
+                icon.setVisibleState(StatusBarIconView.STATE_HIDDEN, true /* animate */,
+                        () -> removeTransientView(icon));
+            }
+        }
+    }
+
+    /**
+     * Finds the first view with a translation bigger then a given value
+     */
+    private int findFirstViewIndexAfter(float translationX) {
+        for (int i = 0; i < getChildCount(); i++) {
+            View view = getChildAt(i);
+            if (view.getTranslationX() > translationX) {
+                return i;
+            }
+        }
+        return getChildCount();
+    }
+
+    public WeakHashMap<View, IconState> resetViewStates() {
+        for (int i = 0; i < getChildCount(); i++) {
+            View view = getChildAt(i);
+            ViewState iconState = mIconStates.get(view);
+            iconState.initFrom(view);
+            iconState.alpha = 1.0f;
+        }
+        return mIconStates;
+    }
+
+    /**
+     * Calulate the horizontal translations for each notification based on how much the icons
+     * are inserted into the notification container.
+     * If this is not a whole number, the fraction means by how much the icon is appearing.
+     */
+    public void calculateIconTranslations() {
+        float translationX = getActualPaddingStart();
+        int overflowingIconIndex = -1;
+        int lastTwoIconWidth = 0;
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View view = getChildAt(i);
+            IconState iconState = mIconStates.get(view);
+            iconState.xTranslation = translationX;
+            iconState.visibleState = StatusBarIconView.STATE_ICON;
+            translationX += iconState.iconAppearAmount * view.getWidth();
+            if (translationX > getLayoutEnd()) {
+                // we are overflowing it with this icon
+                overflowingIconIndex = i - 1;
+                lastTwoIconWidth = view.getWidth();
+                break;
+            }
+        }
+        if (overflowingIconIndex != -1) {
+            int numDots = 1;
+            View overflowIcon = getChildAt(overflowingIconIndex);
+            IconState overflowState = mIconStates.get(overflowIcon);
+            lastTwoIconWidth += overflowIcon.getWidth();
+            int dotWidth = mStaticDotRadius * 2 + mDotPadding;
+            int totalDotLength = mStaticDotRadius * 6 + 2 * mDotPadding;
+            translationX = (getLayoutEnd() - lastTwoIconWidth / 2 - totalDotLength / 2)
+                    - overflowIcon.getWidth() * 0.3f + mStaticDotRadius;
+            float overflowStart = getLayoutEnd() - lastTwoIconWidth;
+            float overlapAmount = (overflowState.xTranslation - overflowStart)
+                    / overflowIcon.getWidth();
+            translationX += overlapAmount * dotWidth;
+            for (int i = overflowingIconIndex; i < childCount; i++) {
+                View view = getChildAt(i);
+                IconState iconState = mIconStates.get(view);
+                iconState.xTranslation = translationX;
+                if (numDots <= 3) {
+                    iconState.visibleState = StatusBarIconView.STATE_DOT;
+                    translationX += numDots == 3 ? 3 * dotWidth : dotWidth;
+                } else {
+                    iconState.visibleState = StatusBarIconView.STATE_HIDDEN;
+                }
+                numDots++;
+            }
+        }
+        if (isLayoutRtl()) {
+            for (int i = 0; i < childCount; i++) {
+                View view = getChildAt(i);
+                IconState iconState = mIconStates.get(view);
+                iconState.xTranslation = getWidth() - iconState.xTranslation - view.getWidth();
+            }
+        }
+    }
+
+    private float getLayoutEnd() {
+        return getActualWidth() - getActualPaddingEnd();
+    }
+
+    private float getActualPaddingEnd() {
+        if (mActualPaddingEnd < 0) {
+            return getPaddingEnd();
+        }
+        return mActualPaddingEnd;
+    }
+
+    private float getActualPaddingStart() {
+        if (mActualPaddingStart < 0) {
+            return getPaddingStart();
+        }
+        return mActualPaddingStart;
+    }
+
+    /**
+     * Sets whether the layout should always show all icons.
+     * If this is true, the icon positions will be updated on layout.
+     * If this if false, the layout is managed from the outside and layouting won't trigger a
+     * repositioning of the icons.
+     */
+    public void setShowAllIcons(boolean showAllIcons) {
+        mShowAllIcons = showAllIcons;
+    }
+
+    public void setActualLayoutWidth(int actualLayoutWidth) {
+        mActualLayoutWidth = actualLayoutWidth;
+        if (DEBUG) {
+            invalidate();
+        }
+    }
+
+    public void setActualPaddingEnd(float paddingEnd) {
+        mActualPaddingEnd = paddingEnd;
+        if (DEBUG) {
+            invalidate();
+        }
+    }
+
+    public void setActualPaddingStart(float paddingStart) {
+        mActualPaddingStart = paddingStart;
+        if (DEBUG) {
+            invalidate();
+        }
+    }
+
+    public int getActualWidth() {
+        if (mActualLayoutWidth < 0) {
+            return getWidth();
+        }
+        return mActualLayoutWidth;
+    }
+
+    public void setChangingViewPositions(boolean changingViewPositions) {
+        mChangingViewPositions = changingViewPositions;
+    }
+
+    public class IconState extends ViewState {
+        public float iconAppearAmount = 1.0f;
+        public int visibleState;
+        public boolean justAdded = true;
+
+        @Override
+        public void applyToView(View view) {
+            if (view instanceof StatusBarIconView) {
+                StatusBarIconView icon = (StatusBarIconView) view;
+                AnimationProperties animationProperties = DOT_ANIMATION_PROPERTIES;
+                if (justAdded) {
+                    super.applyToView(icon);
+                    icon.setAlpha(0.0f);
+                    icon.setVisibleState(StatusBarIconView.STATE_HIDDEN, false /* animate */);
+                    animationProperties = ADD_ICON_PROPERTIES;
+                }
+                boolean animate = visibleState != icon.getVisibleState() || justAdded;
+                if (!animate && mAnimationStartIndex >= 0
+                        && (icon.getVisibleState() != StatusBarIconView.STATE_HIDDEN
+                            || visibleState != StatusBarIconView.STATE_HIDDEN)) {
+                    int viewIndex = indexOfChild(view);
+                    animate = viewIndex >= mAnimationStartIndex;
+                }
+                icon.setVisibleState(visibleState);
+                if (animate) {
+                    animateTo(icon, animationProperties);
+                } else {
+                    super.applyToView(view);
+                }
+            }
+            justAdded = false;
+        }
+    }
+}
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 068631d..99e98f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -202,11 +202,12 @@
     private Runnable mHeadsUpExistenceChangedRunnable = new Runnable() {
         @Override
         public void run() {
-            mHeadsUpAnimatingAway = false;
+            setHeadsUpAnimatingAway(false);
             notifyBarPanelExpansionChanged();
         }
     };
     private NotificationGroupManager mGroupManager;
+    private boolean mOpening;
 
     public NotificationPanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -403,11 +404,9 @@
                 mKeyguardStatusView.getHeight());
         int notificationPadding = Math.max(1, getResources().getDimensionPixelSize(
                 R.dimen.notification_divider_height));
-        final int overflowheight = getResources().getDimensionPixelSize(
-                R.dimen.notification_summary_height);
-        float bottomStackSize = mNotificationStackScroller.getKeyguardBottomStackSize();
-        float availableSpace = mNotificationStackScroller.getHeight() - minPadding - overflowheight
-                - bottomStackSize;
+        float shelfSize = mNotificationStackScroller.getNotificationShelf().getIntrinsicHeight()
+                + notificationPadding;
+        float availableSpace = mNotificationStackScroller.getHeight() - minPadding - shelfSize;
         int count = 0;
         for (int i = 0; i < mNotificationStackScroller.getChildCount(); i++) {
             ExpandableView child = (ExpandableView) mNotificationStackScroller.getChildAt(i);
@@ -429,6 +428,16 @@
             availableSpace -= child.getMinHeight() + notificationPadding;
             if (availableSpace >= 0 && count < maximum) {
                 count++;
+            } else if (availableSpace > -shelfSize) {
+                // if we are exactly the last view, then we can show us still!
+                for (int j = i + 1; j < mNotificationStackScroller.getChildCount(); j++) {
+                    if (mNotificationStackScroller.getChildAt(j)
+                            instanceof ExpandableNotificationRow) {
+                        return count;
+                    }
+                }
+                count++;
+                return count;
             } else {
                 return count;
             }
@@ -546,9 +555,7 @@
     protected void flingToHeight(float vel, boolean expand, float target,
             float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) {
         mHeadsUpTouchHelper.notifyFling(!expand);
-        setClosingWithAlphaFadeout(!expand
-                && mNotificationStackScroller.getFirstChildIntrinsicHeight() <= mMaxFadeoutHeight
-                && getFadeoutAlpha() == 1.0f);
+        setClosingWithAlphaFadeout(!expand && getFadeoutAlpha() == 1.0f);
         super.flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing);
     }
 
@@ -723,6 +730,11 @@
     }
 
     @Override
+    protected float getOpeningHeight() {
+        return mNotificationStackScroller.getMinExpansionHeight();
+    }
+
+    @Override
     public boolean onTouchEvent(MotionEvent event) {
         if (mBlockTouches || (mQs != null && mQs.isCustomizing())) {
             return false;
@@ -1415,7 +1427,7 @@
             if (mKeyguardShowing) {
 
                 // On Keyguard, interpolate the QS expansion linearly to the panel expansion
-                t = expandedHeight / getMaxPanelHeight();
+                t = expandedHeight / (getMaxPanelHeight());
             } else {
 
                 // In Shade, interpolate linearly such that QS is closed whenever panel height is
@@ -1475,9 +1487,7 @@
         // and expanding/collapsing the whole panel from/to quick settings.
         if (mNotificationStackScroller.getNotGoneChildCount() == 0
                 && mShadeEmpty) {
-            notificationHeight = mNotificationStackScroller.getEmptyShadeViewHeight()
-                    + mNotificationStackScroller.getBottomStackPeekSize()
-                    + mNotificationStackScroller.getBottomStackSlowDownHeight();
+            notificationHeight = mNotificationStackScroller.getEmptyShadeViewHeight();
         }
         int maxQsHeight = mQsMaxExpansionHeight;
 
@@ -1508,8 +1518,7 @@
 
     private float getFadeoutAlpha() {
         float alpha = (getNotificationsTopY() + mNotificationStackScroller.getFirstItemMinHeight())
-                / (mQsMinExpansionHeight + mNotificationStackScroller.getBottomStackPeekSize()
-                - mNotificationStackScroller.getBottomStackSlowDownHeight());
+                / mQsMinExpansionHeight;
         alpha = Math.max(0, Math.min(alpha, 1));
         alpha = (float) Math.pow(alpha, 0.75);
         return alpha;
@@ -1988,9 +1997,9 @@
     @Override
     protected float getCannedFlingDurationFactor() {
         if (mQsExpanded) {
-            return 0.7f;
+            return 0.9f;
         } else {
-            return 0.6f;
+            return 0.8f;
         }
     }
 
@@ -2180,16 +2189,22 @@
 
     @Override
     public void onHeadsUpPinnedModeChanged(final boolean inPinnedMode) {
+        mNotificationStackScroller.setInHeadsUpPinnedMode(inPinnedMode);
         if (inPinnedMode) {
             mHeadsUpExistenceChangedRunnable.run();
             updateNotificationTranslucency();
         } else {
-            mHeadsUpAnimatingAway = true;
+            setHeadsUpAnimatingAway(true);
             mNotificationStackScroller.runAfterAnimationFinished(
                     mHeadsUpExistenceChangedRunnable);
         }
     }
 
+    public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
+        mHeadsUpAnimatingAway = headsUpAnimatingAway;
+        mNotificationStackScroller.setHeadsUpAnimatingAway(headsUpAnimatingAway);
+    }
+
     @Override
     public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
         mNotificationStackScroller.generateHeadsUpAnimation(headsUp, true);
@@ -2265,6 +2280,14 @@
     protected void updateExpandedHeight(float expandedHeight) {
         mNotificationStackScroller.setExpandedHeight(expandedHeight);
         updateKeyguardBottomAreaAlpha();
+        setOpening(expandedHeight <= getOpeningHeight());
+    }
+
+    private void setOpening(boolean opening) {
+        if (opening != mOpening) {
+            mOpening = opening;
+            mStatusBar.recomputeDisableFlags(false);
+        }
     }
 
     public void setPanelScrimMinFraction(float minFraction) {
@@ -2316,7 +2339,18 @@
     @Override
     public void setAlpha(float alpha) {
         super.setAlpha(alpha);
-        mNotificationStackScroller.setParentFadingOut(alpha != 1.0f);
+        updateFullyVisibleState();
+    }
+
+    @Override
+    public void setVisibility(int visibility) {
+        super.setVisibility(visibility);
+        updateFullyVisibleState();
+    }
+
+    private void updateFullyVisibleState() {
+        mNotificationStackScroller.setParentNotFullyVisible(getAlpha() != 1.0f
+                || getVisibility() != VISIBLE);
     }
 
     /**
@@ -2358,6 +2392,15 @@
         mGroupManager = groupManager;
     }
 
+    public boolean shouldHideNotificationIcons() {
+        return !mOpening && !isFullyCollapsed();
+    }
+
+    public boolean shouldAnimateIconHiding() {
+        // TODO: handle this correctly, not completely working yet
+        return mNotificationStackScroller.getTranslationX() != 0;
+    }
+
     private final FragmentListener mFragmentListener = new FragmentListener() {
         @Override
         public void onFragmentViewCreated(String tag, Fragment fragment) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index f2c57e5..87a3848 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -118,7 +118,7 @@
         boolean fullyOpened = false;
         if (SPEW) LOG("panelExpansionChanged: start state=%d", mState);
         PanelView pv = mPanel;
-        pv.setVisibility(expanded ? View.VISIBLE : View.INVISIBLE);
+        pv.setVisibility(expanded ? VISIBLE : INVISIBLE);
         // adjust any other panels that may be partially visible
         if (expanded) {
             if (mState == STATE_CLOSED) {
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 3de03b5..f16c834 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.os.SystemClock;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.InputDevice;
@@ -50,6 +51,10 @@
 public abstract class PanelView extends FrameLayout {
     public static final boolean DEBUG = PanelBar.DEBUG;
     public static final String TAG = PanelView.class.getSimpleName();
+    private static final int INITIAL_OPENING_PEEK_DURATION = 200;
+    private static final int PEEK_ANIMATION_DURATION = 360;
+    private long mDownTime;
+    private float mMinExpandHeight;
 
     private final void logf(String fmt, Object... args) {
         Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
@@ -88,6 +93,7 @@
     private ObjectAnimator mPeekAnimator;
     private VelocityTrackerInterface mVelocityTracker;
     private FlingAnimationUtils mFlingAnimationUtils;
+    private FlingAnimationUtils mFlingAnimationUtilsClosing;
     private FalsingManager mFalsingManager;
 
     /**
@@ -106,9 +112,6 @@
     private Interpolator mBounceInterpolator;
     protected KeyguardBottomAreaView mKeyguardBottomArea;
 
-    private boolean mPeekPending;
-    private boolean mCollapseAfterPeek;
-
     /**
      * Speed-up factor to be used when {@link #mFlingCollapseRunnable} runs the next time.
      */
@@ -118,13 +121,6 @@
     private boolean mGestureWaitForTouchSlop;
     private boolean mIgnoreXTouchSlop;
     private boolean mExpandLatencyTracking;
-    private Runnable mPeekRunnable = new Runnable() {
-        @Override
-        public void run() {
-            mPeekPending = false;
-            runPeekAnimation();
-        }
-    };
 
     protected void onExpandingFinished() {
         mBar.onExpandingFinished();
@@ -148,21 +144,17 @@
         }
     }
 
-    private void schedulePeek() {
-        mPeekPending = true;
-        long timeout = ViewConfiguration.getTapTimeout();
-        postOnAnimationDelayed(mPeekRunnable, timeout);
-        notifyBarPanelExpansionChanged();
-    }
-
-    private void runPeekAnimation() {
-        mPeekHeight = getPeekHeight();
+    private void runPeekAnimation(long duration, float peekHeight, boolean collapseWhenFinished) {
+        mPeekHeight = peekHeight;
         if (DEBUG) logf("peek to height=%.1f", mPeekHeight);
         if (mHeightAnimator != null) {
             return;
         }
+        if (mPeekAnimator != null) {
+            mPeekAnimator.cancel();
+        }
         mPeekAnimator = ObjectAnimator.ofFloat(this, "expandedHeight", mPeekHeight)
-                .setDuration(250);
+                .setDuration(duration);
         mPeekAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
         mPeekAnimator.addListener(new AnimatorListenerAdapter() {
             private boolean mCancelled;
@@ -175,10 +167,10 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 mPeekAnimator = null;
-                if (mCollapseAfterPeek && !mCancelled) {
+                if (!mCancelled && collapseWhenFinished) {
                     postOnAnimation(mPostCollapseRunnable);
                 }
-                mCollapseAfterPeek = false;
+
             }
         });
         notifyExpandingStarted();
@@ -189,6 +181,7 @@
     public PanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mFlingAnimationUtils = new FlingAnimationUtils(context, 0.6f);
+        mFlingAnimationUtilsClosing = new FlingAnimationUtils(context, 0.4f);
         mBounceInterpolator = new BounceInterpolator();
         mFalsingManager = FalsingManager.getInstance(context);
     }
@@ -267,11 +260,13 @@
             case MotionEvent.ACTION_DOWN:
                 startExpandMotion(x, y, false /* startTracking */, mExpandedHeight);
                 mJustPeeked = false;
+                mMinExpandHeight = 0.0f;
                 mPanelClosedOnDown = isFullyCollapsed();
                 mHasLayoutedSinceDown = false;
                 mUpdateFlingOnLayout = false;
                 mMotionAborted = false;
                 mPeekTouching = mPanelClosedOnDown;
+                mDownTime = SystemClock.uptimeMillis();
                 mTouchAboveFalsingThreshold = false;
                 mCollapsedAndHeadsUpOnDown = isFullyCollapsed()
                         && mHeadsUpManager.hasPinnedHeadsUp();
@@ -279,16 +274,16 @@
                     initVelocityTracker();
                 }
                 trackMovement(event);
-                if (!mGestureWaitForTouchSlop || (mHeightAnimator != null && !mHintAnimationRunning) ||
-                        mPeekPending || mPeekAnimator != null) {
+                if (!mGestureWaitForTouchSlop || (mHeightAnimator != null && !mHintAnimationRunning)
+                        || mPeekAnimator != null) {
                     cancelHeightAnimator();
                     cancelPeek();
                     mTouchSlopExceeded = (mHeightAnimator != null && !mHintAnimationRunning)
-                            || mPeekPending || mPeekAnimator != null;
+                            || mPeekAnimator != null;
                     onTrackingStarted();
                 }
                 if (isFullyCollapsed() && !mHeadsUpManager.hasPinnedHeadsUp()) {
-                    schedulePeek();
+                    startOpening();
                 }
                 break;
 
@@ -317,7 +312,7 @@
                 // y-component of the gesture, as we have no conflicting horizontal gesture.
                 if (Math.abs(h) > mTouchSlop
                         && (Math.abs(h) > Math.abs(x - mInitialTouchX)
-                                || mIgnoreXTouchSlop)) {
+                        || mIgnoreXTouchSlop)) {
                     mTouchSlopExceeded = true;
                     if (mGestureWaitForTouchSlop && !mTracking && !mCollapsedAndHeadsUpOnDown) {
                         if (!mJustPeeked && mInitialOffsetOnTouch != 0f) {
@@ -325,23 +320,30 @@
                             h = 0;
                         }
                         cancelHeightAnimator();
-                        removeCallbacks(mPeekRunnable);
-                        mPeekPending = false;
                         onTrackingStarted();
                     }
                 }
-                final float newHeight = Math.max(0, h + mInitialOffsetOnTouch);
+                float newHeight = Math.max(0, h + mInitialOffsetOnTouch);
                 if (newHeight > mPeekHeight) {
                     if (mPeekAnimator != null) {
                         mPeekAnimator.cancel();
                     }
                     mJustPeeked = false;
+                } else if (mPeekAnimator == null && mJustPeeked) {
+                    // The initial peek has finished, but we haven't dragged as far yet, lets
+                    // speed it up by starting at the peek height.
+                    mInitialOffsetOnTouch = mExpandedHeight;
+                    mInitialTouchY = y;
+                    mMinExpandHeight = mExpandedHeight;
+                    mJustPeeked = false;
                 }
+                newHeight = Math.max(newHeight, mMinExpandHeight);
                 if (-h >= getFalsingThreshold()) {
                     mTouchAboveFalsingThreshold = true;
                     mUpwardsWhenTresholdReached = isDirectionUpwards(x, y);
                 }
-                if (!mJustPeeked && (!mGestureWaitForTouchSlop || mTracking) && !isTrackingBlocked()) {
+                if (!mJustPeeked && (!mGestureWaitForTouchSlop || mTracking) &&
+                        !isTrackingBlocked()) {
                     setExpandedHeightInternal(newHeight);
                 }
 
@@ -357,6 +359,14 @@
         return !mGestureWaitForTouchSlop || mTracking;
     }
 
+    private void startOpening() {;
+        runPeekAnimation(INITIAL_OPENING_PEEK_DURATION, getOpeningHeight(),
+                false /* collapseWhenFinished */);
+        notifyBarPanelExpansionChanged();
+    }
+
+    protected abstract float getOpeningHeight();
+
     /**
      * @return whether the swiping direction is upwards and above a 45 degree angle compared to the
      * horizontal direction
@@ -418,6 +428,15 @@
             if (mUpdateFlingOnLayout) {
                 mUpdateFlingVelocity = vel;
             }
+        } else if (mPanelClosedOnDown && !mHeadsUpManager.hasPinnedHeadsUp() && !mTracking) {
+            long timePassed = SystemClock.uptimeMillis() - mDownTime;
+            if (timePassed < ViewConfiguration.getLongPressTimeout()) {
+                // Lets show the user that he can actually expand the panel
+                runPeekAnimation(PEEK_ANIMATION_DURATION, getPeekHeight(), true /* collapseWhenFinished */);
+            } else {
+                // We need to collapse the panel since we peeked to the small height.
+                postOnAnimation(mPostCollapseRunnable);
+            }
         } else {
             boolean expands = onEmptySpaceClick(mInitialTouchX);
             onTrackingStopped(expands);
@@ -448,7 +467,6 @@
     protected void onTrackingStarted() {
         endClosing();
         mTracking = true;
-        mCollapseAfterPeek = false;
         mBar.onTrackingStarted();
         notifyExpandingStarted();
         notifyBarPanelExpansionChanged();
@@ -482,7 +500,10 @@
             case MotionEvent.ACTION_DOWN:
                 mStatusBar.userActivity();
                 mAnimatingOnDown = mHeightAnimator != null;
-                if (mAnimatingOnDown && mClosing && !mHintAnimationRunning || mPeekPending || mPeekAnimator != null) {
+                mMinExpandHeight = 0.0f;
+                mDownTime = SystemClock.uptimeMillis();
+                if (mAnimatingOnDown && mClosing && !mHintAnimationRunning
+                        || mPeekAnimator != null) {
                     cancelHeightAnimator();
                     cancelPeek();
                     mTouchSlopExceeded = true;
@@ -639,7 +660,7 @@
     protected void fling(float vel, boolean expand, float collapseSpeedUpFactor,
             boolean expandBecauseOfFalsing) {
         cancelPeek();
-        float target = expand ? getMaxPanelHeight() : 0.0f;
+        float target = expand ? getMaxPanelHeight() : 0;
         if (!expand) {
             mClosing = true;
         }
@@ -672,8 +693,7 @@
                 animator.setDuration(350);
             }
         } else {
-            mFlingAnimationUtils.applyDismissing(animator, mExpandedHeight, target, vel,
-                    getHeight());
+            mFlingAnimationUtilsClosing.apply(animator, mExpandedHeight, target, vel, getHeight());
 
             // Make it shorter if we run a canned animation
             if (vel == 0) {
@@ -742,7 +762,6 @@
                 && mHeightAnimator == null
                 && !isFullyCollapsed()
                 && currentMaxPanelHeight != mExpandedHeight
-                && !mPeekPending
                 && mPeekAnimator == null
                 && !mPeekTouching) {
             setExpandedHeight(currentMaxPanelHeight);
@@ -769,10 +788,8 @@
             }
         }
 
-        mExpandedHeight = Math.max(0, mExpandedHeight);
-        mExpandedFraction = Math.min(1f, fhWithoutOverExpansion == 0
-                ? 0
-                : mExpandedHeight / fhWithoutOverExpansion);
+        mExpandedFraction = Math.min(1f,
+                fhWithoutOverExpansion == 0 ? 0 : mExpandedHeight / fhWithoutOverExpansion);
         onHeightUpdated(mExpandedHeight);
         notifyBarPanelExpansionChanged();
     }
@@ -816,7 +833,7 @@
     }
 
     public boolean isFullyCollapsed() {
-        return mExpandedHeight <= 0;
+        return mExpandedFraction <= 0.0f;
     }
 
     public boolean isCollapsing() {
@@ -833,16 +850,7 @@
 
     public void collapse(boolean delayed, float speedUpFactor) {
         if (DEBUG) logf("collapse: " + this);
-        if (mPeekPending || mPeekAnimator != null) {
-            mCollapseAfterPeek = true;
-            if (mPeekPending) {
-
-                // We know that the whole gesture is just a peek triggered by a simple click, so
-                // better start it now.
-                removeCallbacks(mPeekRunnable);
-                mPeekRunnable.run();
-            }
-        } else if (!isFullyCollapsed() && !mTracking && !mClosing) {
+        if (!isFullyCollapsed() && !mTracking && !mClosing) {
             cancelHeightAnimator();
             notifyExpandingStarted();
 
@@ -866,13 +874,11 @@
     };
 
     public void cancelPeek() {
-        boolean cancelled = mPeekPending;
+        boolean cancelled = false;
         if (mPeekAnimator != null) {
             cancelled = true;
             mPeekAnimator.cancel();
         }
-        removeCallbacks(mPeekRunnable);
-        mPeekPending = false;
 
         if (cancelled) {
             // When peeking, we already tell mBar that we expanded ourselves. Make sure that we also
@@ -1000,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)
@@ -1048,7 +1054,7 @@
     }
 
     protected void notifyBarPanelExpansionChanged() {
-        mBar.panelExpansionChanged(mExpandedFraction, mExpandedFraction > 0f || mPeekPending
+        mBar.panelExpansionChanged(mExpandedFraction, mExpandedFraction > 0f
                 || mPeekAnimator != null || mInstantExpanding || isPanelVisibleBecauseOfHeadsUp()
                 || mTracking || mHeightAnimator != null);
     }
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 6f13ba5..2b74c84 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -164,7 +164,7 @@
 import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.NotificationData.Entry;
-import com.android.systemui.statusbar.NotificationOverflowContainer;
+import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.SignalClusterView;
@@ -197,7 +197,7 @@
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout
         .OnChildLocationsChangedListener;
 import com.android.systemui.statusbar.stack.StackStateAnimator;
-import com.android.systemui.statusbar.stack.StackViewState;
+import com.android.systemui.statusbar.stack.ExpandableViewState;
 import com.android.systemui.volume.VolumeComponent;
 
 import java.io.FileDescriptor;
@@ -569,8 +569,8 @@
      */
     protected boolean mStartedGoingToSleep;
 
-    private static final int VISIBLE_LOCATIONS = StackViewState.LOCATION_FIRST_HUN
-            | StackViewState.LOCATION_MAIN_AREA;
+    private static final int VISIBLE_LOCATIONS = ExpandableViewState.LOCATION_FIRST_HUN
+            | ExpandableViewState.LOCATION_MAIN_AREA;
 
     private final OnChildLocationsChangedListener mNotificationLocationsChangedListener =
             new OnChildLocationsChangedListener() {
@@ -659,10 +659,12 @@
         array.clear();
     }
 
-    private final View.OnClickListener mOverflowClickListener = new View.OnClickListener() {
+    private final View.OnClickListener mShelfClickListener = new View.OnClickListener() {
         @Override
         public void onClick(View v) {
-            goToLockedShade(null);
+            if (mState == StatusBarState.KEYGUARD) {
+                goToLockedShade(null);
+            }
         }
     };
     private HashMap<ExpandableNotificationRow, List<ExpandableNotificationRow>> mTmpChildOrderMap
@@ -812,7 +814,7 @@
         mStackScroller.setHeadsUpManager(mHeadsUpManager);
         mGroupManager.setOnGroupChangeListener(mStackScroller);
 
-        inflateOverflowContainer();
+        inflateShelf();
         inflateEmptyShadeView();
         inflateDismissView();
         mExpandedContents = mStackScroller;
@@ -855,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);
 
@@ -1049,13 +1050,13 @@
         return new BatteryControllerImpl(mContext);
     }
 
-    private void inflateOverflowContainer() {
-        mKeyguardIconOverflowContainer =
-                (NotificationOverflowContainer) LayoutInflater.from(mContext).inflate(
-                        R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false);
-        mKeyguardIconOverflowContainer.setOnActivatedListener(this);
-        mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener);
-        mStackScroller.setOverflowContainer(mKeyguardIconOverflowContainer);
+    private void inflateShelf() {
+        mNotificationShelf =
+                (NotificationShelf) LayoutInflater.from(mContext).inflate(
+                        R.layout.status_bar_notification_shelf, mStackScroller, false);
+        mNotificationShelf.setOnActivatedListener(this);
+        mNotificationShelf.setOnClickListener(mShelfClickListener);
+        mStackScroller.setShelf(mNotificationShelf);
     }
 
     @Override
@@ -1072,7 +1073,6 @@
         updateClearAll();
         inflateEmptyShadeView();
         updateEmptyShadeView();
-        inflateOverflowContainer();
         mStatusBarKeyguardViewManager.onDensityOrFontScaleChanged();
         mUserInfoController.onDensityOrFontScaleChanged();
         if (mUserSwitcherController != null) {
@@ -1866,12 +1866,15 @@
         mTmpChildOrderMap.clear();
 
         updateRowStates();
-        updateSpeedbump();
+        updateSpeedBumpIndex();
         updateClearAll();
         updateEmptyShadeView();
 
         updateQsExpansionEnabled();
         mShadeUpdates.check();
+
+        // Let's also update the icons
+        mIconController.updateNotificationIcons(mNotificationData);
     }
 
     /**
@@ -1987,8 +1990,8 @@
         mNotificationPanel.setShadeEmpty(showEmptyShade);
     }
 
-    private void updateSpeedbump() {
-        int speedbumpIndex = -1;
+    private void updateSpeedBumpIndex() {
+        int speedBumpIndex = -1;
         int currentIndex = 0;
         final int N = mStackScroller.getChildCount();
         for (int i = 0; i < N; i++) {
@@ -1998,12 +2001,17 @@
             }
             ExpandableNotificationRow row = (ExpandableNotificationRow) view;
             if (mNotificationData.isAmbient(row.getStatusBarNotification().getKey())) {
-                speedbumpIndex = currentIndex;
+                speedBumpIndex = currentIndex;
                 break;
             }
             currentIndex++;
         }
-        mStackScroller.updateSpeedBumpIndex(speedbumpIndex);
+        boolean noAmbient = false;
+        if (speedBumpIndex == -1) {
+            speedBumpIndex = currentIndex;
+            noAmbient = true;
+        }
+        mStackScroller.updateSpeedBumpIndex(speedBumpIndex, noAmbient);
     }
 
     public static boolean isTopLevelChild(Entry entry) {
@@ -2015,7 +2023,6 @@
         mNotificationData.filterAndSort();
 
         updateNotificationShade();
-        mIconController.updateNotificationIcons(mNotificationData);
     }
 
     public void requestNotificationUpdate() {
@@ -2375,8 +2382,7 @@
     }
 
     protected int adjustDisableFlags(int state) {
-        if (!mLaunchTransitionFadingAway && !mKeyguardFadingAway
-                && (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit)) {
+        if (!mLaunchTransitionFadingAway && !mKeyguardFadingAway && shouldHideNotificationIcons()) {
             state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
             state |= StatusBarManager.DISABLE_SYSTEM_INFO;
         }
@@ -2391,6 +2397,10 @@
         return state;
     }
 
+    private boolean shouldHideNotificationIcons() {
+        return mExpandedVisible && mNotificationPanel.shouldHideNotificationIcons();
+    }
+
     /**
      * State is one or more of the DISABLE constants from StatusBarManager.
      */
@@ -2497,7 +2507,7 @@
      *
      * This needs to be called if state used by {@link #adjustDisableFlags} changes.
      */
-    private void recomputeDisableFlags(boolean animate) {
+    public void recomputeDisableFlags(boolean animate) {
         disable(mDisabledUnmodified1, mDisabledUnmodified2, animate);
     }
 
@@ -2694,6 +2704,14 @@
         mFalsingManager.onScreenOff();
     }
 
+    public NotificationShelf getNotificationShelf() {
+        return mNotificationShelf;
+    }
+
+    public NotificationStackScrollLayout getNotificationScrollLayout() {
+        return mStackScroller;
+    }
+
     public boolean isPulsing() {
         return mDozeScrimController.isPulsing();
     }
@@ -2935,7 +2953,7 @@
         runPostCollapseRunnables();
         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
         showBouncer();
-        recomputeDisableFlags(true /* animate */);
+        recomputeDisableFlags(shouldAnimatIconHiding() /* animate */);
 
         // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
         // the bouncer appear animation.
@@ -2944,6 +2962,10 @@
         }
     }
 
+    private boolean shouldAnimatIconHiding() {
+        return mNotificationPanel.shouldAnimateIconHiding();
+    }
+
     public boolean interceptTouchEvent(MotionEvent event) {
         if (DEBUG_GESTURES) {
             if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
@@ -4153,7 +4175,7 @@
                 mScrimController.forceHideScrims(true /* hide */);
                 updateMediaMetaData(false, true);
                 mNotificationPanel.setAlpha(1);
-                mStackScroller.setParentFadingOut(true);
+                mStackScroller.setParentNotFullyVisible(true);
                 mNotificationPanel.animate()
                         .alpha(0)
                         .setStartDelay(FADE_KEYGUARD_START_DELAY)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index fc15477..8fd6bbf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -335,12 +335,16 @@
             QSTile<?> tile = mTiles.get(tileSpec);
             if (tile != null && (!(tile instanceof CustomTile)
                     || ((CustomTile) tile).getUser() == currentUser)) {
-                if (DEBUG) Log.d(TAG, "Adding " + tile);
-                tile.removeCallbacks();
-                if (!(tile instanceof CustomTile) && mCurrentUser != currentUser) {
-                    tile.userSwitch(currentUser);
+                if (tile.isAvailable()) {
+                    if (DEBUG) Log.d(TAG, "Adding " + tile);
+                    tile.removeCallbacks();
+                    if (!(tile instanceof CustomTile) && mCurrentUser != currentUser) {
+                        tile.userSwitch(currentUser);
+                    }
+                    newTiles.put(tileSpec, tile);
+                } else {
+                    tile.destroy();
                 }
-                newTiles.put(tileSpec, tile);
             } else {
                 if (DEBUG) Log.d(TAG, "Creating tile: " + tileSpec);
                 try {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index a4b76ebb..0e74e57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -21,7 +21,6 @@
 import android.animation.PropertyValuesHolder;
 import android.animation.ValueAnimator;
 import android.content.Context;
-import android.graphics.Color;
 import android.graphics.Rect;
 import android.support.v4.graphics.ColorUtils;
 import android.view.View;
@@ -37,7 +36,7 @@
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.stack.StackStateAnimator;
+import com.android.systemui.statusbar.stack.ViewState;
 
 /**
  * Controls both the scrim behind the notifications and in front of the notifications (when a
@@ -79,7 +78,7 @@
     private boolean mWakeAndUnlocking;
     protected boolean mAnimateChange;
     private boolean mUpdatePending;
-    private boolean mExpanding;
+    private boolean mTracking;
     private boolean mAnimateKeyguardFadingOut;
     protected long mDurationOverride = -1;
     private long mAnimationDelay;
@@ -123,12 +122,12 @@
     }
 
     public void onTrackingStarted() {
-        mExpanding = true;
+        mTracking = true;
         mDarkenWhileDragging = !mUnlockMethodCache.canSkipBouncer();
     }
 
     public void onExpandingFinished() {
-        mExpanding = false;
+        mTracking = false;
     }
 
     public void setPanelExpansion(float fraction) {
@@ -138,7 +137,7 @@
             if (mPinnedHeadsUpCount != 0) {
                 updateHeadsUpScrim(false);
             }
-            if (mKeyguardFadeoutAnimation != null) {
+            if (mKeyguardFadeoutAnimation != null && mTracking) {
                 mKeyguardFadeoutAnimation.cancel();
             }
         }
@@ -146,7 +145,7 @@
 
     public void setBouncerShowing(boolean showing) {
         mBouncerShowing = showing;
-        mAnimateChange = !mExpanding && !mDontAnimateBouncerChanges;
+        mAnimateChange = !mTracking && !mDontAnimateBouncerChanges;
         scheduleUpdate();
     }
 
@@ -269,7 +268,7 @@
     }
 
     private void updateScrimKeyguard() {
-        if (mExpanding && mDarkenWhileDragging) {
+        if (mTracking && mDarkenWhileDragging) {
             float behindFraction = Math.max(0, Math.min(mFraction, 1));
             float fraction = 1 - behindFraction;
             fraction = (float) Math.pow(fraction, 0.8f);
@@ -278,7 +277,7 @@
             setScrimBehindColor(behindFraction * mScrimBehindAlphaKeyguard);
         } else if (mBouncerShowing && !mBouncerIsKeyguard) {
             setScrimInFrontColor(getScrimInFrontAlpha());
-            setScrimBehindColor(0f);
+            updateScrimNormal();
         } else if (mBouncerShowing) {
             setScrimInFrontColor(0f);
             setScrimBehindColor(mScrimBehindAlpha);
@@ -474,18 +473,18 @@
     }
 
     private void updateScrim(boolean animate, View scrim, float alpha, float currentAlpha) {
-        if (mKeyguardFadingOutInProgress) {
+        if (mKeyguardFadingOutInProgress && mKeyguardFadeoutAnimation.getCurrentPlayTime() != 0) {
             return;
         }
 
-        ValueAnimator previousAnimator = StackStateAnimator.getChildTag(scrim,
+        ValueAnimator previousAnimator = ViewState.getChildTag(scrim,
                 TAG_KEY_ANIM);
         float animEndValue = -1;
         if (previousAnimator != null) {
             if (animate || alpha == currentAlpha) {
                 previousAnimator.cancel();
             } else {
-                animEndValue = StackStateAnimator.getChildTag(scrim, TAG_END_ALPHA);
+                animEndValue = ViewState.getChildTag(scrim, TAG_END_ALPHA);
             }
         }
         if (alpha != currentAlpha && alpha != animEndValue) {
@@ -495,10 +494,8 @@
                 scrim.setTag(TAG_END_ALPHA, alpha);
             } else {
                 if (previousAnimator != null) {
-                    float previousStartValue = StackStateAnimator.getChildTag(scrim,
-                            TAG_START_ALPHA);
-                    float previousEndValue = StackStateAnimator.getChildTag(scrim,
-                            TAG_END_ALPHA);
+                    float previousStartValue = ViewState.getChildTag(scrim, TAG_START_ALPHA);
+                    float previousEndValue = ViewState.getChildTag(scrim, TAG_END_ALPHA);
                     // we need to increase all animation keyframes of the previous animator by the
                     // relative change to the end value
                     PropertyValuesHolder[] values = previousAnimator.getValues();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index dbe7f96..a948a08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -44,6 +44,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.SignalClusterView;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.tuner.TunerService;
@@ -74,6 +75,7 @@
 
     private NotificationIconAreaController mNotificationIconAreaController;
     private View mNotificationIconAreaInner;
+    private NotificationShelf mNotificationShelf;
 
     private BatteryMeterView mBatteryMeterView;
     private BatteryMeterView mBatteryMeterViewKeyguard;
@@ -123,6 +125,7 @@
         mStatusIcons = (LinearLayout) statusBar.findViewById(R.id.statusIcons);
         mSignalCluster = (SignalClusterView) statusBar.findViewById(R.id.signal_cluster);
 
+        mNotificationShelf = phoneStatusBar.getNotificationShelf();
         mNotificationIconAreaController = SystemUIFactory.getInstance()
                 .createNotificationIconAreaController(context, phoneStatusBar);
         mNotificationIconAreaInner =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 69decd7..4263670 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -33,6 +33,7 @@
 import com.android.systemui.DejankUtils;
 import com.android.keyguard.LatencyTracker;
 import com.android.systemui.SystemUIFactory;
+import com.android.systemui.keyguard.DismissCallbackRegistry;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.RemoteInputController;
 
@@ -102,14 +103,15 @@
     public void registerStatusBar(PhoneStatusBar phoneStatusBar,
             ViewGroup container, StatusBarWindowManager statusBarWindowManager,
             ScrimController scrimController,
-            FingerprintUnlockController fingerprintUnlockController) {
+            FingerprintUnlockController fingerprintUnlockController,
+            DismissCallbackRegistry dismissCallbackRegistry) {
         mPhoneStatusBar = phoneStatusBar;
         mContainer = container;
         mStatusBarWindowManager = statusBarWindowManager;
         mScrimController = scrimController;
         mFingerprintUnlockController = fingerprintUnlockController;
         mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
-                mViewMediatorCallback, mLockPatternUtils, mStatusBarWindowManager, container);
+                mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry);
     }
 
     /**
@@ -330,17 +332,21 @@
             });
         } else {
             executeAfterKeyguardGoneAction();
-            if (mFingerprintUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING) {
-                mFingerprintUnlockController.startKeyguardFadingAway();
-                mPhoneStatusBar.setKeyguardFadingAway(startTime, 0, 240);
+            boolean wakeUnlockPulsing =
+                    mFingerprintUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING;
+            if (wakeUnlockPulsing) {
+                delay = 0;
+                fadeoutDuration = 240;
+            }
+            mPhoneStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
+            mFingerprintUnlockController.startKeyguardFadingAway();
+            mBouncer.hide(true /* destroyView */);
+            updateStates();
+            if (wakeUnlockPulsing) {
                 mStatusBarWindowManager.setKeyguardFadingAway(true);
                 mPhoneStatusBar.fadeKeyguardWhilePulsing();
-                animateScrimControllerKeyguardFadingOut(0, 240, new Runnable() {
-                    @Override
-                    public void run() {
-                        mPhoneStatusBar.hideKeyguard();
-                    }
-                }, false /* skipFirstFrame */);
+                animateScrimControllerKeyguardFadingOut(delay, fadeoutDuration,
+                        mPhoneStatusBar::hideKeyguard, false /* skipFirstFrame */);
             } else {
                 mFingerprintUnlockController.startKeyguardFadingAway();
                 mPhoneStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
@@ -367,9 +373,7 @@
                 }
             }
             mStatusBarWindowManager.setKeyguardShowing(false);
-            mBouncer.hide(true /* destroyView */);
             mViewMediatorCallback.keyguardGone();
-            updateStates();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 6217433..f6dd88d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -235,7 +235,7 @@
     @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
         if (ev.getActionMasked() == MotionEvent.ACTION_DOWN
-                && mNotificationPanel.getExpandedHeight() == 0f) {
+                && mNotificationPanel.isFullyCollapsed()) {
             mNotificationPanel.startExpandLatencyTracking();
         }
         mFalsingManager.onTouchEvent(ev, getWidth(), getHeight());
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/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index f6c0942..c21c493 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -103,6 +103,7 @@
     private boolean mWaitingOnCollapseWhenGoingAway;
     private boolean mIsObserving;
     private boolean mRemoteInputActive;
+    private float mExpandedHeight;
 
     public HeadsUpManager(final Context context, View statusBarWindowView,
                           NotificationGroupManager groupManager) {
@@ -513,7 +514,7 @@
                 row = groupSummary;
             }
         }
-        return row.getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
+        return row.getPinnedHeadsUpHeight();
     }
 
     /**
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/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index fafbdd1..0396613 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -92,20 +92,6 @@
         return mCanSkipBouncer;
     }
 
-    public void unlock() {
-        try {
-            WindowManagerGlobal.getWindowManagerService().dismissKeyguard();
-        } catch (RemoteException e) {
-        }
-    }
-
-    public void lock() {
-        try {
-            WindowManagerGlobal.getWindowManagerService().lockNow(null /* options */);
-        } catch (RemoteException e) {
-        }
-    }
-
     public void notifyKeyguardState(boolean showing, boolean secure, boolean occluded) {
         if (mShowing == showing && mSecure == secure && mOccluded == occluded) return;
         mShowing = showing;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
index 43ced48..69281b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
@@ -23,6 +23,7 @@
     boolean hasProfileOwner();
     String getDeviceOwnerName();
     String getProfileOwnerName();
+    CharSequence getDeviceOwnerOrganizationName();
     boolean isVpnEnabled();
     boolean isVpnRestricted();
     /** Whether the VPN app should use branded VPN iconography.  */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index 07d3b59..142f21b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -130,6 +130,11 @@
     }
 
     @Override
+    public CharSequence getDeviceOwnerOrganizationName() {
+        return mDevicePolicyManager.getDeviceOwnerOrganizationName();
+    }
+
+    @Override
     public String getPrimaryVpnName() {
         VpnConfig cfg = mCurrentVpns.get(mVpnUserId);
         if (cfg != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index 81da672..26f74ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -16,9 +16,12 @@
 
 package com.android.systemui.statusbar.stack;
 
+import android.content.Context;
 import android.view.View;
 
+import com.android.systemui.R;
 import com.android.systemui.statusbar.ActivatableNotificationView;
+import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import java.util.ArrayList;
@@ -44,6 +47,38 @@
     private float mMaxHeadsUpTranslation;
     private boolean mDismissAllInProgress;
     private int mLayoutMinHeight;
+    private NotificationShelf mShelf;
+    private int mZDistanceBetweenElements;
+    private int mBaseZHeight;
+    private int mMaxLayoutHeight;
+    private ActivatableNotificationView mLastVisibleBackgroundChild;
+
+    public AmbientState(Context context) {
+        reload(context);
+    }
+
+    /**
+     * Reload the dimens e.g. if the density changed.
+     */
+    public void reload(Context context) {
+        mZDistanceBetweenElements = Math.max(1, context.getResources()
+                .getDimensionPixelSize(R.dimen.z_distance_between_notifications));
+        mBaseZHeight = 4 * mZDistanceBetweenElements;
+    }
+
+    /**
+     * @return the basic Z height on which notifications remain.
+     */
+    public int getBaseZHeight() {
+        return mBaseZHeight;
+    }
+
+    /**
+     * @return the distance in Z between two overlaying notifications.
+     */
+    public int getZDistanceBetweenElements() {
+        return mZDistanceBetweenElements;
+    }
 
     public int getScrollY() {
         return mScrollY;
@@ -122,8 +157,8 @@
         return mSpeedBumpIndex;
     }
 
-    public void setSpeedBumpIndex(int speedBumpIndex) {
-        mSpeedBumpIndex = speedBumpIndex;
+    public void setSpeedBumpIndex(int shelfIndex) {
+        mSpeedBumpIndex = shelfIndex;
     }
 
     public void setHeadsUpManager(HeadsUpManager headsUpManager) {
@@ -151,7 +186,7 @@
     }
 
     public int getInnerHeight() {
-        return Math.max(mLayoutHeight - mTopPadding, mLayoutMinHeight);
+        return Math.max(Math.min(mLayoutHeight, mMaxLayoutHeight) - mTopPadding, mLayoutMinHeight);
     }
 
     public boolean isShadeExpanded() {
@@ -181,4 +216,29 @@
     public void setLayoutMinHeight(int layoutMinHeight) {
         mLayoutMinHeight = layoutMinHeight;
     }
+
+    public void setShelf(NotificationShelf shelf) {
+        mShelf = shelf;
+    }
+
+    public NotificationShelf getShelf() {
+        return mShelf;
+    }
+
+    public void setLayoutMaxHeight(int maxLayoutHeight) {
+        mMaxLayoutHeight = maxLayoutHeight;
+    }
+
+    /**
+     * Sets the last visible view of the host layout, that has a background, i.e the very last
+     * view in the shade, without the clear all button.
+     */
+    public void setLastVisibleBackgroundChild(
+            ActivatableNotificationView lastVisibleBackgroundChild) {
+        mLastVisibleBackgroundChild = lastVisibleBackgroundChild;
+    }
+
+    public ActivatableNotificationView getLastVisibleBackgroundChild() {
+        return mLastVisibleBackgroundChild;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
index 561b18a..d3d58f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
@@ -23,6 +23,7 @@
  */
 public class AnimationFilter {
     boolean animateAlpha;
+    boolean animateX;
     boolean animateY;
     boolean animateZ;
     boolean animateHeight;
@@ -42,6 +43,11 @@
         return this;
     }
 
+    public AnimationFilter animateX() {
+        animateX = true;
+        return this;
+    }
+
     public AnimationFilter animateY() {
         animateY = true;
         return this;
@@ -116,6 +122,7 @@
 
     private void combineFilter(AnimationFilter filter) {
         animateAlpha |= filter.animateAlpha;
+        animateX |= filter.animateX;
         animateY |= filter.animateY;
         animateZ |= filter.animateZ;
         animateHeight |= filter.animateHeight;
@@ -129,6 +136,7 @@
 
     private void reset() {
         animateAlpha = false;
+        animateX = false;
         animateY = false;
         animateZ = false;
         animateHeight = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationProperties.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationProperties.java
new file mode 100644
index 0000000..0de774d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationProperties.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.stack;
+
+import android.animation.AnimatorListenerAdapter;
+import android.util.Property;
+import android.view.View;
+import android.view.animation.Interpolator;
+
+/**
+ * Properties for a View animation
+ */
+public class AnimationProperties {
+    public long duration;
+    public long delay;
+
+    /**
+     * @return an animation filter for this animation.
+     */
+    public AnimationFilter getAnimationFilter() {
+        return new AnimationFilter();
+    }
+
+    /**
+     * @return a listener that should be run whenever any property finished its animation
+     */
+    public AnimatorListenerAdapter getAnimationFinishListener() {
+        return null;
+    }
+
+    public boolean wasAdded(View view) {
+        return false;
+    }
+
+    /**
+     * Get a custom interpolator for a property instead of the normal one.
+     */
+    public Interpolator getCustomInterpolator(View child, Property property) {
+        return null;
+    }
+
+    public AnimationProperties setDuration(long duration) {
+        this.duration = duration;
+        return this;
+    }
+
+    public AnimationProperties setDelay(long delay) {
+        this.delay = delay;
+        return this;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java
new file mode 100644
index 0000000..7854c98
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.stack;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+import android.view.View;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.ExpandableView;
+
+/**
+* A state of an expandable view
+*/
+public class ExpandableViewState extends ViewState {
+
+    private static final int TAG_ANIMATOR_HEIGHT = R.id.height_animator_tag;
+    private static final int TAG_ANIMATOR_TOP_INSET = R.id.top_inset_animator_tag;
+    private static final int TAG_ANIMATOR_SHADOW_ALPHA = R.id.shadow_alpha_animator_tag;
+    private static final int TAG_END_HEIGHT = R.id.height_animator_end_value_tag;
+    private static final int TAG_END_TOP_INSET = R.id.top_inset_animator_end_value_tag;
+    private static final int TAG_END_SHADOW_ALPHA = R.id.shadow_alpha_animator_end_value_tag;
+    private static final int TAG_START_HEIGHT = R.id.height_animator_start_value_tag;
+    private static final int TAG_START_TOP_INSET = R.id.top_inset_animator_start_value_tag;
+    private static final int TAG_START_SHADOW_ALPHA = R.id.shadow_alpha_animator_start_value_tag;
+
+    // These are flags such that we can create masks for filtering.
+
+    /**
+     * No known location. This is the default and should not be set after an invocation of the
+     * algorithm.
+     */
+    public static final int LOCATION_UNKNOWN = 0x00;
+
+    /**
+     * The location is the first heads up notification, so on the very top.
+     */
+    public static final int LOCATION_FIRST_HUN = 0x01;
+
+    /**
+     * The location is hidden / scrolled away on the top.
+     */
+    public static final int LOCATION_HIDDEN_TOP = 0x02;
+
+    /**
+     * The location is in the main area of the screen and visible.
+     */
+    public static final int LOCATION_MAIN_AREA = 0x04;
+
+    /**
+     * The location is in the bottom stack and it's peeking
+     */
+    public static final int LOCATION_BOTTOM_STACK_PEEKING = 0x08;
+
+    /**
+     * The location is in the bottom stack and it's hidden.
+     */
+    public static final int LOCATION_BOTTOM_STACK_HIDDEN = 0x10;
+
+    /**
+     * The view isn't laid out at all.
+     */
+    public static final int LOCATION_GONE = 0x40;
+
+    public int height;
+    public boolean dimmed;
+    public boolean dark;
+    public boolean hideSensitive;
+    public boolean belowSpeedBump;
+    public float shadowAlpha;
+    public boolean inShelf;
+
+    /**
+     * How much the child overlaps with the previous child on top. This is used to
+     * show the background properly when the child on top is translating away.
+     */
+    public int clipTopAmount;
+
+    /**
+     * The index of the view, only accounting for views not equal to GONE
+     */
+    public int notGoneIndex;
+
+    /**
+     * The location this view is currently rendered at.
+     *
+     * <p>See <code>LOCATION_</code> flags.</p>
+     */
+    public int location;
+
+    @Override
+    public void copyFrom(ViewState viewState) {
+        super.copyFrom(viewState);
+        if (viewState instanceof ExpandableViewState) {
+            ExpandableViewState svs = (ExpandableViewState) viewState;
+            height = svs.height;
+            dimmed = svs.dimmed;
+            shadowAlpha = svs.shadowAlpha;
+            dark = svs.dark;
+            hideSensitive = svs.hideSensitive;
+            belowSpeedBump = svs.belowSpeedBump;
+            clipTopAmount = svs.clipTopAmount;
+            notGoneIndex = svs.notGoneIndex;
+            location = svs.location;
+        }
+    }
+
+    /**
+     * Applies a {@link ExpandableViewState} to a {@link ExpandableView}.
+     */
+    @Override
+    public void applyToView(View view) {
+        super.applyToView(view);
+        if (view instanceof ExpandableView) {
+            ExpandableView expandableView = (ExpandableView) view;
+
+            int height = expandableView.getActualHeight();
+            int newHeight = this.height;
+
+            // apply height
+            if (height != newHeight) {
+                expandableView.setActualHeight(newHeight, false /* notifyListeners */);
+            }
+
+            float shadowAlpha = expandableView.getShadowAlpha();
+            float newShadowAlpha = this.shadowAlpha;
+
+            // apply shadowAlpha
+            if (shadowAlpha != newShadowAlpha) {
+                expandableView.setShadowAlpha(newShadowAlpha);
+            }
+
+            // apply dimming
+            expandableView.setDimmed(this.dimmed, false /* animate */);
+
+            // apply hiding sensitive
+            expandableView.setHideSensitive(
+                    this.hideSensitive, false /* animated */, 0 /* delay */, 0 /* duration */);
+
+            // apply below shelf speed bump
+            expandableView.setBelowSpeedBump(this.belowSpeedBump);
+
+            // apply dark
+            expandableView.setDark(this.dark, false /* animate */, 0 /* delay */);
+
+            // apply clipping
+            float oldClipTopAmount = expandableView.getClipTopAmount();
+            if (oldClipTopAmount != this.clipTopAmount) {
+                expandableView.setClipTopAmount(this.clipTopAmount);
+            }
+
+            expandableView.setTransformingInShelf(false);
+            expandableView.setInShelf(inShelf);
+        }
+    }
+
+    @Override
+    public void animateTo(View child, AnimationProperties properties) {
+        super.animateTo(child, properties);
+        if (!(child instanceof ExpandableView)) {
+            return;
+        }
+        ExpandableView expandableView = (ExpandableView) child;
+        AnimationFilter animationFilter = properties.getAnimationFilter();
+
+        // start height animation
+        if (this.height != expandableView.getActualHeight()) {
+            startHeightAnimation(expandableView, properties);
+        }  else {
+            abortAnimation(child, TAG_ANIMATOR_HEIGHT);
+        }
+
+        // start shadow alpha animation
+        if (this.shadowAlpha != expandableView.getShadowAlpha()) {
+            startShadowAlphaAnimation(expandableView, properties);
+        } else {
+            abortAnimation(child, TAG_ANIMATOR_SHADOW_ALPHA);
+        }
+
+        // start top inset animation
+        if (this.clipTopAmount != expandableView.getClipTopAmount()) {
+            startInsetAnimation(expandableView, properties);
+        } else {
+            abortAnimation(child, TAG_ANIMATOR_TOP_INSET);
+        }
+
+        // start dimmed animation
+        expandableView.setDimmed(this.dimmed, animationFilter.animateDimmed);
+
+        // apply below the speed bump
+        expandableView.setBelowSpeedBump(this.belowSpeedBump);
+
+        // start hiding sensitive animation
+        expandableView.setHideSensitive(this.hideSensitive, animationFilter.animateHideSensitive,
+                properties.delay, properties.duration);
+
+        // start dark animation
+        expandableView.setDark(this.dark, animationFilter.animateDark, properties.delay);
+
+        if (properties.wasAdded(child) && !hidden) {
+            expandableView.performAddAnimation(properties.delay, properties.duration);
+        }
+
+        if (!expandableView.isInShelf() && this.inShelf) {
+            expandableView.setTransformingInShelf(true);
+        }
+        expandableView.setInShelf(this.inShelf);
+    }
+
+    private void startHeightAnimation(final ExpandableView child, AnimationProperties properties) {
+        Integer previousStartValue = getChildTag(child, TAG_START_HEIGHT);
+        Integer previousEndValue = getChildTag(child, TAG_END_HEIGHT);
+        int newEndValue = this.height;
+        if (previousEndValue != null && previousEndValue == newEndValue) {
+            return;
+        }
+        ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_HEIGHT);
+        AnimationFilter filter = properties.getAnimationFilter();
+        if (!filter.animateHeight) {
+            // just a local update was performed
+            if (previousAnimator != null) {
+                // we need to increase all animation keyframes of the previous animator by the
+                // relative change to the end value
+                PropertyValuesHolder[] values = previousAnimator.getValues();
+                int relativeDiff = newEndValue - previousEndValue;
+                int newStartValue = previousStartValue + relativeDiff;
+                values[0].setIntValues(newStartValue, newEndValue);
+                child.setTag(TAG_START_HEIGHT, newStartValue);
+                child.setTag(TAG_END_HEIGHT, newEndValue);
+                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+                return;
+            } else {
+                // no new animation needed, let's just apply the value
+                child.setActualHeight(newEndValue, false);
+                return;
+            }
+        }
+
+        ValueAnimator animator = ValueAnimator.ofInt(child.getActualHeight(), newEndValue);
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                child.setActualHeight((int) animation.getAnimatedValue(),
+                        false /* notifyListeners */);
+            }
+        });
+        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+        long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator);
+        animator.setDuration(newDuration);
+        if (properties.delay > 0 && (previousAnimator == null
+                || previousAnimator.getAnimatedFraction() == 0)) {
+            animator.setStartDelay(properties.delay);
+        }
+        AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+        if (listener != null) {
+            animator.addListener(listener);
+        }
+        // remove the tag when the animation is finished
+        animator.addListener(new AnimatorListenerAdapter() {
+            boolean mWasCancelled;
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                child.setTag(TAG_ANIMATOR_HEIGHT, null);
+                child.setTag(TAG_START_HEIGHT, null);
+                child.setTag(TAG_END_HEIGHT, null);
+                child.setActualHeightAnimating(false);
+                if (!mWasCancelled && child instanceof ExpandableNotificationRow) {
+                    ((ExpandableNotificationRow) child).setGroupExpansionChanging(
+                            false /* isExpansionChanging */);
+                }
+            }
+
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mWasCancelled = false;
+            }
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                mWasCancelled = true;
+            }
+        });
+        startAnimator(animator, listener);
+        child.setTag(TAG_ANIMATOR_HEIGHT, animator);
+        child.setTag(TAG_START_HEIGHT, child.getActualHeight());
+        child.setTag(TAG_END_HEIGHT, newEndValue);
+        child.setActualHeightAnimating(true);
+    }
+
+    private void startShadowAlphaAnimation(final ExpandableView child,
+            AnimationProperties properties) {
+        Float previousStartValue = getChildTag(child, TAG_START_SHADOW_ALPHA);
+        Float previousEndValue = getChildTag(child, TAG_END_SHADOW_ALPHA);
+        float newEndValue = this.shadowAlpha;
+        if (previousEndValue != null && previousEndValue == newEndValue) {
+            return;
+        }
+        ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_SHADOW_ALPHA);
+        AnimationFilter filter = properties.getAnimationFilter();
+        if (!filter.animateShadowAlpha) {
+            // just a local update was performed
+            if (previousAnimator != null) {
+                // we need to increase all animation keyframes of the previous animator by the
+                // relative change to the end value
+                PropertyValuesHolder[] values = previousAnimator.getValues();
+                float relativeDiff = newEndValue - previousEndValue;
+                float newStartValue = previousStartValue + relativeDiff;
+                values[0].setFloatValues(newStartValue, newEndValue);
+                child.setTag(TAG_START_SHADOW_ALPHA, newStartValue);
+                child.setTag(TAG_END_SHADOW_ALPHA, newEndValue);
+                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+                return;
+            } else {
+                // no new animation needed, let's just apply the value
+                child.setShadowAlpha(newEndValue);
+                return;
+            }
+        }
+
+        ValueAnimator animator = ValueAnimator.ofFloat(child.getShadowAlpha(), newEndValue);
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                child.setShadowAlpha((float) animation.getAnimatedValue());
+            }
+        });
+        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+        long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator);
+        animator.setDuration(newDuration);
+        if (properties.delay > 0 && (previousAnimator == null
+                || previousAnimator.getAnimatedFraction() == 0)) {
+            animator.setStartDelay(properties.delay);
+        }
+        AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+        if (listener != null) {
+            animator.addListener(listener);
+        }
+        // remove the tag when the animation is finished
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                child.setTag(TAG_ANIMATOR_SHADOW_ALPHA, null);
+                child.setTag(TAG_START_SHADOW_ALPHA, null);
+                child.setTag(TAG_END_SHADOW_ALPHA, null);
+            }
+        });
+        startAnimator(animator, listener);
+        child.setTag(TAG_ANIMATOR_SHADOW_ALPHA, animator);
+        child.setTag(TAG_START_SHADOW_ALPHA, child.getShadowAlpha());
+        child.setTag(TAG_END_SHADOW_ALPHA, newEndValue);
+    }
+
+    private void startInsetAnimation(final ExpandableView child, AnimationProperties properties) {
+        Integer previousStartValue = getChildTag(child, TAG_START_TOP_INSET);
+        Integer previousEndValue = getChildTag(child, TAG_END_TOP_INSET);
+        int newEndValue = this.clipTopAmount;
+        if (previousEndValue != null && previousEndValue == newEndValue) {
+            return;
+        }
+        ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TOP_INSET);
+        AnimationFilter filter = properties.getAnimationFilter();
+        if (!filter.animateTopInset) {
+            // just a local update was performed
+            if (previousAnimator != null) {
+                // we need to increase all animation keyframes of the previous animator by the
+                // relative change to the end value
+                PropertyValuesHolder[] values = previousAnimator.getValues();
+                int relativeDiff = newEndValue - previousEndValue;
+                int newStartValue = previousStartValue + relativeDiff;
+                values[0].setIntValues(newStartValue, newEndValue);
+                child.setTag(TAG_START_TOP_INSET, newStartValue);
+                child.setTag(TAG_END_TOP_INSET, newEndValue);
+                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+                return;
+            } else {
+                // no new animation needed, let's just apply the value
+                child.setClipTopAmount(newEndValue);
+                return;
+            }
+        }
+
+        ValueAnimator animator = ValueAnimator.ofInt(child.getClipTopAmount(), newEndValue);
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                child.setClipTopAmount((int) animation.getAnimatedValue());
+            }
+        });
+        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+        long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator);
+        animator.setDuration(newDuration);
+        if (properties.delay > 0 && (previousAnimator == null
+                || previousAnimator.getAnimatedFraction() == 0)) {
+            animator.setStartDelay(properties.delay);
+        }
+        AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+        if (listener != null) {
+            animator.addListener(listener);
+        }
+        // remove the tag when the animation is finished
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                child.setTag(TAG_ANIMATOR_TOP_INSET, null);
+                child.setTag(TAG_START_TOP_INSET, null);
+                child.setTag(TAG_END_TOP_INSET, null);
+            }
+        });
+        startAnimator(animator, listener);
+        child.setTag(TAG_ANIMATOR_TOP_INSET, animator);
+        child.setTag(TAG_START_TOP_INSET, child.getClipTopAmount());
+        child.setTag(TAG_END_TOP_INSET, newEndValue);
+    }
+
+    /**
+     * Get the end value of the height animation running on a view or the actualHeight
+     * if no animation is running.
+     */
+    public static int getFinalActualHeight(ExpandableView view) {
+        if (view == null) {
+            return 0;
+        }
+        ValueAnimator heightAnimator = getChildTag(view, TAG_ANIMATOR_HEIGHT);
+        if (heightAnimator == null) {
+            return view.getActualHeight();
+        } else {
+            return getChildTag(view, TAG_END_HEIGHT);
+        }
+    }
+}
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 d7920a9..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);
@@ -185,6 +186,11 @@
     }
 
     @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+
+    @Override
     public boolean pointInView(float localX, float localY, float slop) {
         return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) &&
                 localY < (mRealHeight + slop);
@@ -207,6 +213,7 @@
         mDividers.add(newIndex, divider);
 
         updateGroupOverflow();
+        row.setIconTransformationAmount(0, false /* isLastChild */);
     }
 
     public void removeNotification(ExpandableNotificationRow row) {
@@ -412,7 +419,7 @@
      * @param resultState the state to update
      * @param parentState the state of the parent
      */
-    public void getState(StackScrollState resultState, StackViewState parentState) {
+    public void getState(StackScrollState resultState, ExpandableViewState parentState) {
         int childCount = mChildren.size();
         int yPosition = mNotificationHeaderMargin;
         boolean firstChild = true;
@@ -427,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) {
@@ -449,22 +455,11 @@
                 firstChild = false;
             }
 
-            StackViewState childState = resultState.getViewStateForView(child);
+            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
@@ -530,7 +525,7 @@
      * @return true if children after this one should be hidden.
      */
     private boolean updateChildStateForExpandedGroup(ExpandableNotificationRow child,
-            int parentHeight, StackViewState childState, int yPosition) {
+            int parentHeight, ExpandableViewState childState, int yPosition) {
         final int top = yPosition + child.getClipTopAmount();
         final int intrinsicHeight = child.getIntrinsicHeight();
         final int bottom = top + intrinsicHeight;
@@ -570,8 +565,8 @@
                 || mNotificationParent.isGroupExpansionChanging();
         for (int i = 0; i < childCount; i++) {
             ExpandableNotificationRow child = mChildren.get(i);
-            StackViewState viewState = state.getViewStateForView(child);
-            state.applyState(child, viewState);
+            ExpandableViewState viewState = state.getViewStateForView(child);
+            viewState.applyToView(child);
 
             // layout the divider
             View divider = mDividers.get(i);
@@ -584,16 +579,44 @@
             }
             tmpState.hidden = !dividersVisible;
             tmpState.alpha = alpha;
-            state.applyViewState(divider, tmpState);
+            tmpState.applyToView(divider);
             // There is no fake shadow to be drawn on the children
             child.setFakeShadowIntensity(0.0f, 0.0f, 0, 0);
         }
-        if (mOverflowNumber != null) {
-            state.applyViewState(mOverflowNumber, mGroupOverFlowState);
+        if (mGroupOverFlowState != null) {
+            mGroupOverFlowState.applyToView(mOverflowNumber);
             mNeverAppliedGroupState = false;
         }
-        if (mNotificationHeader != null) {
-            state.applyViewState(mNotificationHeader, mHeaderViewState);
+        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);
         }
     }
 
@@ -608,8 +631,7 @@
         return;
     }
 
-    public void startAnimationToState(StackScrollState state, StackStateAnimator stateAnimator,
-            long baseDelay, long duration) {
+    public void startAnimationToState(StackScrollState state, AnimationProperties properties) {
         int childCount = mChildren.size();
         ViewState tmpState = new ViewState();
         float expandFraction = getGroupExpandFraction();
@@ -617,8 +639,8 @@
                 || mNotificationParent.isGroupExpansionChanging();
         for (int i = childCount - 1; i >= 0; i--) {
             ExpandableNotificationRow child = mChildren.get(i);
-            StackViewState viewState = state.getViewStateForView(child);
-            stateAnimator.startStackAnimations(child, viewState, state, -1, baseDelay);
+            ExpandableViewState viewState = state.getViewStateForView(child);
+            viewState.animateTo(child, properties);
 
             // layout the divider
             View divider = mDividers.get(i);
@@ -631,7 +653,7 @@
             }
             tmpState.hidden = !dividersVisible;
             tmpState.alpha = alpha;
-            stateAnimator.startViewAnimations(divider, tmpState, baseDelay, duration);
+            tmpState.animateTo(divider, properties);
             // There is no fake shadow to be drawn on the children
             child.setFakeShadowIntensity(0.0f, 0.0f, 0, 0);
         }
@@ -639,16 +661,16 @@
             if (mNeverAppliedGroupState) {
                 float alpha = mGroupOverFlowState.alpha;
                 mGroupOverFlowState.alpha = 0;
-                state.applyViewState(mOverflowNumber, mGroupOverFlowState);
+                mGroupOverFlowState.applyToView(mOverflowNumber);
                 mGroupOverFlowState.alpha = alpha;
                 mNeverAppliedGroupState = false;
             }
-            stateAnimator.startViewAnimations(mOverflowNumber, mGroupOverFlowState,
-                    baseDelay, duration);
+            mGroupOverFlowState.animateTo(mOverflowNumber, properties);
         }
         if (mNotificationHeader != null) {
-            state.applyViewState(mNotificationHeader, mHeaderViewState);
+            mHeaderViewState.applyToView(mNotificationHeader);
         }
+        updateChildrenClipping();
     }
 
     public ExpandableNotificationRow getViewAtPosition(float y) {
@@ -876,4 +898,18 @@
         }
         return 0;
     }
+
+    public void setIconsVisible(boolean iconsVisible) {
+        if (mNotificationHeaderWrapper != null) {
+            NotificationHeaderView header = mNotificationHeaderWrapper.getNotificationHeader();
+            if (header != null) {
+                header.getIcon().setForceHidden(!iconsVisible);
+            }
+        }
+    }
+
+    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 72a0e59..10d995c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -69,9 +69,9 @@
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
 import com.android.systemui.statusbar.NotificationGuts;
-import com.android.systemui.statusbar.NotificationOverflowContainer;
 import com.android.systemui.statusbar.NotificationSettingsIconRow;
 import com.android.systemui.statusbar.NotificationSettingsIconRow.SettingsIconRowListener;
+import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.StackScrollerDecorView;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.FakeShadowView;
@@ -135,8 +135,6 @@
     private Paint mDebugPaint;
     private int mContentHeight;
     private int mCollapsedSize;
-    private int mBottomStackSlowDownHeight;
-    private int mBottomStackPeekSize;
     private int mPaddingBetweenElements;
     private int mIncreasedPaddingBetweenElements;
     private int mTopPadding;
@@ -151,7 +149,7 @@
      * The current State this Layout is in
      */
     private StackScrollState mCurrentStackScrollState = new StackScrollState(this);
-    private AmbientState mAmbientState = new AmbientState();
+    private final AmbientState mAmbientState;
     private NotificationGroupManager mGroupManager;
     private HashSet<View> mChildrenToAddAnimated = new HashSet<>();
     private ArrayList<View> mAddedHeadsUpChildren = new ArrayList<>();
@@ -261,18 +259,14 @@
     private boolean mTrackingHeadsUp;
     private ScrimController mScrimController;
     private boolean mForceNoOverlappingRendering;
-    private NotificationOverflowContainer mOverflowContainer;
     private final ArrayList<Pair<ExpandableNotificationRow, Boolean>> mTmpList = new ArrayList<>();
     private FalsingManager mFalsingManager;
     private boolean mAnimationRunning;
-    private ViewTreeObserver.OnPreDrawListener mBackgroundUpdater
+    private ViewTreeObserver.OnPreDrawListener mRunningAnimationUpdater
             = new ViewTreeObserver.OnPreDrawListener() {
         @Override
         public boolean onPreDraw() {
-            // if it needs animation
-            if (!mNeedsAnimation && !mChildrenUpdateRequested) {
-                updateBackground();
-            }
+            onPreDrawDuringAnimation();
             return true;
         }
     };
@@ -334,7 +328,7 @@
     private boolean mPulsing;
     private boolean mDrawBackgroundAsSrc;
     private boolean mFadingOut;
-    private boolean mParentFadingOut;
+    private boolean mParentNotFullyVisible;
     private boolean mGroupExpandedForMeasure;
     private boolean mScrollable;
     private View mForcedScroll;
@@ -354,6 +348,15 @@
     private boolean mQsExpanded;
     private boolean mForwardScrollable;
     private boolean mBackwardScrollable;
+    private NotificationShelf mShelf;
+    private int mMaxDisplayedNotifications = -1;
+    private int mStatusBarHeight;
+    private boolean mNoAmbient;
+    private final Rect mClipRect = new Rect();
+    private boolean mIsClipped;
+    private Rect mRequestedClipBounds;
+    private boolean mInHeadsUpPinnedMode;
+    private boolean mHeadsUpAnimatingAway;
 
     public NotificationStackScrollLayout(Context context) {
         this(context, null);
@@ -370,6 +373,7 @@
     public NotificationStackScrollLayout(Context context, AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+        mAmbientState = new AmbientState(context);
         mBgColor = context.getColor(R.color.notification_shade_background_color);
         int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height);
         int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_max_height);
@@ -418,11 +422,6 @@
         if (DEBUG) {
             int y = mTopPadding;
             canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
-            y = (int) (getLayoutHeight() - mBottomStackPeekSize
-                    - mBottomStackSlowDownHeight);
-            canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
-            y = (int) (getLayoutHeight() - mBottomStackPeekSize);
-            canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
             y = (int) getLayoutHeight();
             canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
             y = getHeight() - getEmptyBottomMargin();
@@ -459,16 +458,15 @@
         mOverflingDistance = configuration.getScaledOverflingDistance();
         mCollapsedSize = context.getResources()
                 .getDimensionPixelSize(R.dimen.notification_min_height);
-        mBottomStackPeekSize = context.getResources()
-                .getDimensionPixelSize(R.dimen.bottom_stack_peek_amount);
         mStackScrollAlgorithm.initView(context);
+        mAmbientState.reload(context);
         mPaddingBetweenElements = Math.max(1, context.getResources()
                 .getDimensionPixelSize(R.dimen.notification_divider_height));
         mIncreasedPaddingBetweenElements = context.getResources()
                 .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
-        mBottomStackSlowDownHeight = mStackScrollAlgorithm.getBottomStackSlowDownLength();
         mMinTopOverScrollToEscape = getResources().getDimensionPixelSize(
                 R.dimen.min_top_overscroll_to_qs);
+        mStatusBarHeight = getResources().getDimensionPixelOffset(R.dimen.status_bar_height);
     }
 
     public void setDrawBackgroundAsSrc(boolean asSrc) {
@@ -477,7 +475,7 @@
     }
 
     private void updateSrcDrawing() {
-        mBackgroundPaint.setXfermode(mDrawBackgroundAsSrc && (!mFadingOut && !mParentFadingOut)
+        mBackgroundPaint.setXfermode(mDrawBackgroundAsSrc && !mFadingOut && !mParentNotFullyVisible
                 ? mSrcMode : null);
         invalidate();
     }
@@ -529,8 +527,9 @@
         }
     }
 
-    public void updateSpeedBumpIndex(int newIndex) {
+    public void updateSpeedBumpIndex(int newIndex, boolean noAmbient) {
         mAmbientState.setSpeedBumpIndex(newIndex);
+        mNoAmbient = noAmbient;
     }
 
     public void setChildLocationsChangedListener(OnChildLocationsChangedListener listener) {
@@ -541,21 +540,22 @@
      * Returns the location the given child is currently rendered at.
      *
      * @param child the child to get the location for
-     * @return one of {@link StackViewState}'s <code>LOCATION_*</code> constants
+     * @return one of {@link ExpandableViewState}'s <code>LOCATION_*</code> constants
      */
     public int getChildLocation(View child) {
-        StackViewState childViewState = mCurrentStackScrollState.getViewStateForView(child);
+        ExpandableViewState childViewState = mCurrentStackScrollState.getViewStateForView(child);
         if (childViewState == null) {
-            return StackViewState.LOCATION_UNKNOWN;
+            return ExpandableViewState.LOCATION_UNKNOWN;
         }
         if (childViewState.gone) {
-            return StackViewState.LOCATION_GONE;
+            return ExpandableViewState.LOCATION_GONE;
         }
         return childViewState.location;
     }
 
     private void setMaxLayoutHeight(int maxLayoutHeight) {
         mMaxLayoutHeight = maxLayoutHeight;
+        mShelf.setMaxLayoutHeight(maxLayoutHeight);
         updateAlgorithmHeightAndPadding();
     }
 
@@ -584,6 +584,13 @@
         }
     }
 
+    private void onPreDrawDuringAnimation() {
+        mShelf.updateAppearance();
+        if (!mNeedsAnimation && !mChildrenUpdateRequested) {
+            updateBackground();
+        }
+    }
+
     private void updateScrollStateForAddedChildren() {
         if (mChildrenToAddAnimated.isEmpty()) {
             return;
@@ -671,7 +678,18 @@
      */
     public void setExpandedHeight(float height) {
         mExpandedHeight = height;
-        setIsExpanded(height > 0.0f);
+        setIsExpanded(height > 0);
+        int minExpansionHeight = getMinExpansionHeight();
+        if (height < minExpansionHeight) {
+            mClipRect.left = 0;
+            mClipRect.right = getWidth();
+            mClipRect.top = 0;
+            mClipRect.bottom = (int) height;
+            height = minExpansionHeight;
+            setRequestedClipBounds(mClipRect);
+        } else {
+            setRequestedClipBounds(null);
+        }
         int stackHeight;
         float translationY;
         float appearEndPosition = getAppearEndPosition();
@@ -697,6 +715,26 @@
             requestChildrenUpdate();
         }
         setStackTranslation(translationY);
+        requestChildrenUpdate();
+    }
+
+    private void setRequestedClipBounds(Rect clipRect) {
+        mRequestedClipBounds = clipRect;
+        updateClipping();
+    }
+
+    public void updateClipping() {
+        boolean clipped = mRequestedClipBounds != null && !mInHeadsUpPinnedMode
+                && !mHeadsUpAnimatingAway;
+        if (mIsClipped != clipped) {
+            mIsClipped = clipped;
+            updateFadingState();
+        }
+        if (clipped) {
+            setClipBounds(mRequestedClipBounds);
+        } else {
+            setClipBounds(null);
+        }
     }
 
     /**
@@ -704,13 +742,7 @@
      *         Measured relative to the resting position.
      */
     private float getExpandTranslationStart() {
-        int startPosition = 0;
-        if (!mTrackingHeadsUp && !mHeadsUpManager.hasPinnedHeadsUp()) {
-            startPosition = - Math.min(getFirstChildIntrinsicHeight(),
-                    mMaxLayoutHeight - mIntrinsicPadding - mBottomStackSlowDownHeight
-                            - mBottomStackPeekSize);
-        }
-        return startPosition - mTopPadding;
+        return - mTopPadding;
     }
 
     /**
@@ -718,9 +750,14 @@
      *         Measured in absolute height.
      */
     private float getAppearStartPosition() {
-        return mTrackingHeadsUp
-                ? mHeadsUpManager.getTopHeadsUpPinnedHeight()
-                : 0;
+        if (mTrackingHeadsUp && mFirstVisibleBackgroundChild != null) {
+            if (mFirstVisibleBackgroundChild.isAboveShelf()) {
+                // If we ever expanded beyond the first notification, it's allowed to merge into
+                // the shelf
+                return mFirstVisibleBackgroundChild.getPinnedHeadsUpHeight();
+            }
+        }
+        return getMinExpansionHeight();
     }
 
     /**
@@ -728,11 +765,18 @@
      *         Measured in absolute height.
      */
     private float getAppearEndPosition() {
-        int firstItemHeight = mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp()
-                ? mHeadsUpManager.getTopHeadsUpPinnedHeight() + mBottomStackPeekSize
-                        + mBottomStackSlowDownHeight
-                : getLayoutMinHeight();
-        return firstItemHeight + (onKeyguard() ? mTopPadding : mIntrinsicPadding);
+        int appearPosition;
+        int minNotificationsForShelf = 1;
+        if (mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp()) {
+            appearPosition = mHeadsUpManager.getTopHeadsUpPinnedHeight();
+            minNotificationsForShelf = 2;
+        } else {
+            appearPosition = 0;
+        }
+        if (getNotGoneChildCount() >= minNotificationsForShelf) {
+            appearPosition += mShelf.getIntrinsicHeight();
+        }
+        return appearPosition + (onKeyguard() ? mTopPadding : mIntrinsicPadding);
     }
 
     /**
@@ -773,14 +817,6 @@
         return firstChild != null ? firstChild.getMinHeight() : mCollapsedSize;
     }
 
-    public int getBottomStackPeekSize() {
-        return mBottomStackPeekSize;
-    }
-
-    public int getBottomStackSlowDownHeight() {
-        return mBottomStackSlowDownHeight;
-    }
-
     public void setLongPressListener(SwipeHelper.LongPressListener listener) {
         mSwipeHelper.setLongPressListener(listener);
         mLongPressListener = listener;
@@ -957,7 +993,8 @@
             }
             float childTop = slidingChild.getTranslationY();
             float top = childTop + slidingChild.getClipTopAmount();
-            float bottom = childTop + slidingChild.getActualHeight();
+            float bottom = childTop + slidingChild.getActualHeight()
+                    - slidingChild.getClipBottomAmount();
 
             float dist = Math.min(Math.abs(top - localTouchY), Math.abs(bottom - localTouchY));
             if (dist < minDist) {
@@ -986,7 +1023,8 @@
             }
             float childTop = slidingChild.getTranslationY();
             float top = childTop + slidingChild.getClipTopAmount();
-            float bottom = childTop + slidingChild.getActualHeight();
+            float bottom = childTop + slidingChild.getActualHeight()
+                    - slidingChild.getClipBottomAmount();
 
             // Allow the full width of this view to prevent gesture conflict on Keyguard (phone and
             // camera affordance).
@@ -1056,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);
-            StackViewState 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) {
@@ -1748,8 +1764,7 @@
 
     private int getScrollRange() {
         int contentHeight = getContentHeight();
-        int scrollRange = Math.max(0, contentHeight - mMaxLayoutHeight + mBottomStackPeekSize
-                + mBottomStackSlowDownHeight);
+        int scrollRange = Math.max(0, contentHeight - mMaxLayoutHeight);
         int imeInset = getImeInset();
         scrollRange += Math.min(imeInset, Math.max(0,
                 getContentHeight() - (getHeight() - imeInset)));
@@ -1767,7 +1782,7 @@
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
-            if (child.getVisibility() != View.GONE) {
+            if (child.getVisibility() != View.GONE && child != mShelf) {
                 return (ExpandableView) child;
             }
         }
@@ -1814,7 +1829,7 @@
         int childCount = getChildCount();
         for (int i = childCount - 1; i >= 0; i--) {
             View child = getChildAt(i);
-            if (child.getVisibility() != View.GONE) {
+            if (child.getVisibility() != View.GONE && child != mShelf) {
                 return child;
             }
         }
@@ -1829,7 +1844,7 @@
         int count = 0;
         for (int i = 0; i < childCount; i++) {
             ExpandableView child = (ExpandableView) getChildAt(i);
-            if (child.getVisibility() != View.GONE && !child.willBeGone()) {
+            if (child.getVisibility() != View.GONE && !child.willBeGone() && child != mShelf) {
                 count++;
             }
         }
@@ -1843,9 +1858,17 @@
     private void updateContentHeight() {
         int height = 0;
         float previousIncreasedAmount = 0.0f;
+        int numShownItems = 0;
+        boolean finish = false;
         for (int i = 0; i < getChildCount(); i++) {
             ExpandableView expandableView = (ExpandableView) getChildAt(i);
-            if (expandableView.getVisibility() != View.GONE) {
+            if (expandableView.getVisibility() != View.GONE
+                    && !expandableView.hasNoContentHeight()) {
+                if (mMaxDisplayedNotifications != -1
+                        && numShownItems >= mMaxDisplayedNotifications) {
+                    expandableView = mShelf;
+                    finish = true;
+                }
                 float increasedPaddingAmount = expandableView.getIncreasedPaddingAmount();
                 if (height != 0) {
                     height += (int) NotificationUtils.interpolate(
@@ -1855,10 +1878,15 @@
                 }
                 previousIncreasedAmount = increasedPaddingAmount;
                 height += expandableView.getIntrinsicHeight();
+                numShownItems++;
+                if (finish) {
+                    break;
+                }
             }
         }
         mContentHeight = height + mTopPadding;
         updateScrollability();
+        mAmbientState.setLayoutMaxHeight(mContentHeight);
     }
 
     private void updateScrollability() {
@@ -2036,7 +2064,7 @@
 
     private void applyCurrentBackgroundBounds() {
         mScrimController.setExcludedBackgroundArea(
-                mFadingOut || mParentFadingOut || mAmbientState.isDark() ? null
+                mFadingOut || mParentNotFullyVisible || mAmbientState.isDark() || mIsClipped ? null
                         : mCurrentBounds);
         invalidate();
     }
@@ -2056,7 +2084,7 @@
         ActivatableNotificationView firstView = mFirstVisibleBackgroundChild;
         int top = 0;
         if (firstView != null) {
-            int finalTranslationY = (int) StackStateAnimator.getFinalTranslationY(firstView);
+            int finalTranslationY = (int) ViewState.getFinalTranslationY(firstView);
             if (mAnimateNextBackgroundTop
                     || mTopAnimator == null && mCurrentBounds.top == finalTranslationY
                     || mTopAnimator != null && mEndAnimationRect.top == finalTranslationY) {
@@ -2066,12 +2094,19 @@
                 top = (int) firstView.getTranslationY();
             }
         }
-        ActivatableNotificationView lastView = mLastVisibleBackgroundChild;
+        ActivatableNotificationView lastView = mShelf.hasItemsInStableShelf()
+                ? mShelf
+                : mLastVisibleBackgroundChild;
         int bottom = 0;
         if (lastView != null) {
-            int finalTranslationY = (int) StackStateAnimator.getFinalTranslationY(lastView);
-            int finalHeight = StackStateAnimator.getFinalActualHeight(lastView);
-            int finalBottom = finalTranslationY + finalHeight;
+            int finalTranslationY;
+            if (lastView == mShelf) {
+                finalTranslationY = (int) mShelf.getTranslationY();
+            } else {
+                finalTranslationY = (int) ViewState.getFinalTranslationY(lastView);
+            }
+            int finalHeight = ExpandableViewState.getFinalActualHeight(lastView);
+            int finalBottom = finalTranslationY + finalHeight - lastView.getClipBottomAmount();
             finalBottom = Math.min(finalBottom, getHeight());
             if (mAnimateNextBackgroundBottom
                     || mBottomAnimator == null && mCurrentBounds.bottom == finalBottom
@@ -2079,7 +2114,8 @@
                 // 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());
             }
         } else {
@@ -2115,8 +2151,8 @@
         int childCount = getChildCount();
         for (int i = childCount - 1; i >= 0; i--) {
             View child = getChildAt(i);
-            if (child.getVisibility() != View.GONE
-                    && child instanceof ActivatableNotificationView) {
+            if (child.getVisibility() != View.GONE && child instanceof ActivatableNotificationView
+                    && child != mShelf) {
                 return (ActivatableNotificationView) child;
             }
         }
@@ -2127,8 +2163,8 @@
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
-            if (child.getVisibility() != View.GONE
-                    && child instanceof ActivatableNotificationView) {
+            if (child.getVisibility() != View.GONE && child instanceof ActivatableNotificationView
+                    && child != mShelf) {
                 return (ActivatableNotificationView) child;
             }
         }
@@ -2211,9 +2247,7 @@
     }
 
     public int getLayoutMinHeight() {
-        int firstChildMinHeight = getFirstChildIntrinsicHeight();
-        return Math.min(firstChildMinHeight + mBottomStackPeekSize + mBottomStackSlowDownHeight,
-                mMaxLayoutHeight - mIntrinsicPadding);
+        return mShelf.getIntrinsicHeight();
     }
 
     public int getFirstChildIntrinsicHeight() {
@@ -2237,8 +2271,11 @@
         final ExpandableView firstChild = getFirstChildNotGone();
         final int firstChildMinHeight = firstChild != null ? firstChild.getCollapsedHeight()
                 : mCollapsedSize;
-        return mIntrinsicPadding + firstChildMinHeight + mBottomStackPeekSize
-                + mBottomStackSlowDownHeight;
+        int shelfHeight = 0;
+        if (mLastVisibleBackgroundChild != null) {
+            shelfHeight = mShelf.getIntrinsicHeight();
+        }
+        return mIntrinsicPadding + firstChildMinHeight + shelfHeight;
     }
 
     private int clampPadding(int desiredPadding) {
@@ -2467,7 +2504,7 @@
         if (hasAddEvent) {
             // This child was just added lets remove all events.
             mHeadsUpChangeAnimations.removeAll(mTmpList);
-            ((ExpandableNotificationRow ) child).setHeadsupDisappearRunning(false);
+            ((ExpandableNotificationRow ) child).setHeadsUpAnimatingAway(false);
         }
         mTmpList.clear();
         return hasAddEvent;
@@ -2536,7 +2573,7 @@
         for (int i = 0; i < getChildCount(); i++) {
             ExpandableView child = (ExpandableView) getChildAt(i);
             boolean notGone = child.getVisibility() != View.GONE;
-            if (notGone) {
+            if (notGone && !child.hasNoContentHeight()) {
                 float increasedPaddingAmount = child.getIncreasedPaddingAmount();
                 if (position != 0) {
                     position += (int) NotificationUtils.interpolate(
@@ -2577,6 +2614,7 @@
         }
         mFirstVisibleBackgroundChild = firstChild;
         mLastVisibleBackgroundChild = lastChild;
+        mAmbientState.setLastVisibleBackgroundChild(lastChild);
     }
 
     private void onViewAddedInternal(View child) {
@@ -2727,10 +2765,10 @@
                         : AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR;
                 if (row.isChildInGroup()) {
                     // We can otherwise get stuck in there if it was just isolated
-                    row.setHeadsupDisappearRunning(false);
+                    row.setHeadsUpAnimatingAway(false);
                 }
             } else {
-                StackViewState viewState = mCurrentStackScrollState.getViewStateForView(row);
+                ExpandableViewState viewState = mCurrentStackScrollState.getViewStateForView(row);
                 if (viewState == null) {
                     // A view state was never generated for this view, so we don't need to animate
                     // this. This may happen with notification children.
@@ -2755,7 +2793,7 @@
         mAddedHeadsUpChildren.clear();
     }
 
-    private boolean shouldHunAppearFromBottom(StackViewState viewState) {
+    private boolean shouldHunAppearFromBottom(ExpandableViewState viewState) {
         if (viewState.yTranslation + viewState.height < mAmbientState.getMaxHeadsUpTranslation()) {
             return false;
         }
@@ -3078,14 +3116,7 @@
     }
 
     public int getEmptyBottomMargin() {
-        int emptyMargin = mMaxLayoutHeight - mContentHeight - mBottomStackPeekSize
-                - mBottomStackSlowDownHeight;
-        return Math.max(emptyMargin, 0);
-    }
-
-    public float getKeyguardBottomStackSize() {
-        return mBottomStackPeekSize + getResources().getDimensionPixelSize(
-                R.dimen.bottom_stack_slow_down_length);
+        return Math.max(mMaxLayoutHeight - mContentHeight, 0);
     }
 
     public void onExpansionStarted() {
@@ -3195,20 +3226,18 @@
                 if (row.isChildInGroup()) {
                     endPosition += row.getNotificationParent().getTranslationY();
                 }
-                int stackEnd = getStackEndPosition();
-                if (endPosition > stackEnd) {
-                    setOwnScrollY((int) (mOwnScrollY + endPosition - stackEnd));
+                int layoutEnd = mMaxLayoutHeight + (int) mStackTranslation;
+                if (row != mLastVisibleBackgroundChild) {
+                    layoutEnd -= mShelf.getIntrinsicHeight() + mPaddingBetweenElements;
+                }
+                if (endPosition > layoutEnd) {
+                    setOwnScrollY((int) (mOwnScrollY + endPosition - layoutEnd));
                     mDisallowScrollingInThisMotion = true;
                 }
             }
         }
     }
 
-    private int getStackEndPosition() {
-        return mMaxLayoutHeight - mBottomStackPeekSize - mBottomStackSlowDownHeight
-                + mPaddingBetweenElements + (int) mStackTranslation;
-    }
-
     public void setOnHeightChangedListener(
             ExpandableView.OnHeightChangedListener mOnHeightChangedListener) {
         this.mOnHeightChangedListener = mOnHeightChangedListener;
@@ -3231,10 +3260,10 @@
             View view = getChildAt(i);
             if (view instanceof ExpandableNotificationRow) {
                 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
-                row.setHeadsupDisappearRunning(false);
+                row.setHeadsUpAnimatingAway(false);
                 if (row.isSummaryWithChildren()) {
                     for (ExpandableNotificationRow child : row.getNotificationChildren()) {
-                        child.setHeadsupDisappearRunning(false);
+                        child.setHeadsUpAnimatingAway(false);
                     }
                 }
             }
@@ -3538,50 +3567,6 @@
         }
     }
 
-    public void setOverflowContainer(NotificationOverflowContainer overFlowContainer) {
-        int index = -1;
-        if (mOverflowContainer != null) {
-            index = indexOfChild(mOverflowContainer);
-            removeView(mOverflowContainer);
-        }
-        mOverflowContainer = overFlowContainer;
-        addView(mOverflowContainer, index);
-    }
-
-    public void updateOverflowContainerVisibility(boolean visible) {
-        int oldVisibility = mOverflowContainer.willBeGone() ? GONE
-                : mOverflowContainer.getVisibility();
-        final int newVisibility = visible ? VISIBLE : GONE;
-        if (oldVisibility != newVisibility) {
-            Runnable onFinishedRunnable = new Runnable() {
-                @Override
-                public void run() {
-                    mOverflowContainer.setVisibility(newVisibility);
-                    mOverflowContainer.setWillBeGone(false);
-                    updateContentHeight();
-                    notifyHeightChangeListener(mOverflowContainer);
-                }
-            };
-            if (!mAnimationsEnabled || !mIsExpanded) {
-                mOverflowContainer.cancelAppearDrawing();
-                onFinishedRunnable.run();
-            } else if (newVisibility != GONE) {
-                mOverflowContainer.performAddAnimation(0,
-                        StackStateAnimator.ANIMATION_DURATION_STANDARD);
-                mOverflowContainer.setVisibility(newVisibility);
-                mOverflowContainer.setWillBeGone(false);
-                updateContentHeight();
-                notifyHeightChangeListener(mOverflowContainer);
-            } else {
-                mOverflowContainer.performRemoveAnimation(
-                        StackStateAnimator.ANIMATION_DURATION_STANDARD,
-                        0.0f,
-                        onFinishedRunnable);
-                mOverflowContainer.setWillBeGone(true);
-            }
-        }
-    }
-
     public void updateDismissView(boolean visible) {
         int oldVisibility = mDismissView.willBeGone() ? GONE : mDismissView.getVisibility();
         int newVisibility = visible ? VISIBLE : GONE;
@@ -3663,7 +3648,8 @@
             if (child.getVisibility() == GONE) {
                 continue;
             }
-            float bottom = child.getTranslationY() + child.getActualHeight();
+            float bottom = child.getTranslationY() + child.getActualHeight()
+                    - child.getClipBottomAmount();
             if (bottom > max) {
                 max = bottom;
             }
@@ -3701,7 +3687,8 @@
                     // we are above a notification entirely let's abort
                     return false;
                 }
-                boolean belowChild = touchY > childTop + child.getActualHeight();
+                boolean belowChild = touchY > childTop + child.getActualHeight()
+                        - child.getClipBottomAmount();
                 if (child == mDismissView) {
                     if(!belowChild && !mDismissView.isOnEmptySpace(touchX - mDismissView.getX(),
                                     touchY - childTop)) {
@@ -3795,7 +3782,7 @@
                 // fall through
             case android.R.id.accessibilityActionScrollUp:
                 final int viewportHeight = getHeight() - mPaddingBottom - mTopPadding - mPaddingTop
-                        - mBottomStackPeekSize - mBottomStackSlowDownHeight;
+                        - mShelf.getIntrinsicHeight();
                 final int targetScrollY = Math.max(0,
                         Math.min(mOwnScrollY + direction * viewportHeight, getScrollRange()));
                 if (targetScrollY != mOwnScrollY) {
@@ -3835,7 +3822,7 @@
             mHeadsUpChangeAnimations.add(new Pair<>(row, isHeadsUp));
             mNeedsAnimation = true;
             if (!mIsExpanded && !isHeadsUp) {
-                row.setHeadsupDisappearRunning(true);
+                row.setHeadsUpAnimatingAway(true);
             }
             requestChildrenUpdate();
         }
@@ -3885,9 +3872,9 @@
     public void setAnimationRunning(boolean animationRunning) {
         if (animationRunning != mAnimationRunning) {
             if (animationRunning) {
-                getViewTreeObserver().addOnPreDrawListener(mBackgroundUpdater);
+                getViewTreeObserver().addOnPreDrawListener(mRunningAnimationUpdater);
             } else {
-                getViewTreeObserver().removeOnPreDrawListener(mBackgroundUpdater);
+                getViewTreeObserver().removeOnPreDrawListener(mRunningAnimationUpdater);
             }
             mAnimationRunning = animationRunning;
             updateContinuousShadowDrawing();
@@ -3910,9 +3897,13 @@
         }
     }
 
-    public void setParentFadingOut(boolean fadingOut) {
-        if (fadingOut != mParentFadingOut) {
-            mParentFadingOut = fadingOut;
+    public void setParentNotFullyVisible(boolean parentNotFullyVisible) {
+        if (mScrimController == null) {
+            // we're not set up yet.
+            return;
+        }
+        if (parentNotFullyVisible != mParentNotFullyVisible) {
+            mParentNotFullyVisible = parentNotFullyVisible;
             updateFadingState();
         }
     }
@@ -3949,6 +3940,45 @@
         }
     }
 
+    public void setShelf(NotificationShelf shelf) {
+        int index = -1;
+        if (mShelf != null) {
+            index = indexOfChild(mShelf);
+            removeView(mShelf);
+        }
+        mShelf = shelf;
+        addView(mShelf, index);
+        mAmbientState.setShelf(shelf);
+        mStateAnimator.setShelf(shelf);
+        shelf.bind(mAmbientState, this);
+    }
+
+    public NotificationShelf getNotificationShelf() {
+        return mShelf;
+    }
+
+    public void setMaxDisplayedNotifications(int maxDisplayedNotifications) {
+        if (mMaxDisplayedNotifications != maxDisplayedNotifications) {
+            mMaxDisplayedNotifications = maxDisplayedNotifications;
+            updateContentHeight();
+            notifyHeightChangeListener(mShelf);
+        }
+    }
+
+    public int getMinExpansionHeight() {
+        return mShelf.getIntrinsicHeight() - (mShelf.getIntrinsicHeight() - mStatusBarHeight) / 2;
+    }
+
+    public void setInHeadsUpPinnedMode(boolean inHeadsUpPinnedMode) {
+        mInHeadsUpPinnedMode = inHeadsUpPinnedMode;
+        updateClipping();
+    }
+
+    public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
+        mHeadsUpAnimatingAway = headsUpAnimatingAway;
+        updateClipping();
+    }
+
     /**
      * A listener that is notified when some child locations might have changed.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/PiecewiseLinearIndentationFunctor.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/PiecewiseLinearIndentationFunctor.java
deleted file mode 100644
index 1c37c35..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/PiecewiseLinearIndentationFunctor.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.stack;
-
-import java.util.ArrayList;
-
-/**
- * A Functor which interpolates the stack distance linearly based on base values.
- * The base values are based on an interpolation between a linear function and a
- * quadratic function
- */
-public class PiecewiseLinearIndentationFunctor extends StackIndentationFunctor {
-
-    private final ArrayList<Float> mBaseValues;
-    private final float mLinearPart;
-
-    /**
-     * @param maxItemsInStack The maximum number of items which should be visible at the same time,
-     *                        i.e the function returns totalTransitionDistance for the element with
-     *                        index maxItemsInStack
-     * @param peekSize The visual appearance of this is how far the cards in the stack peek
-     *                 out below the top card and it is measured in real pixels.
-     *                 Note that the visual appearance does not necessarily always correspond to
-     *                 the actual visual distance below the top card but is a maximum,
-     *                 achieved when the next card just starts transitioning into the stack and
-     *                 the stack is full.
-     *                 If distanceToPeekStart is 0, we directly start at the peek, otherwise the
-     *                 first element transitions between 0 and distanceToPeekStart.
-     *                 Visualization:
-     *           ---------------------------------------------------   ---
-     *          |                                                   |   |
-     *          |                  FIRST ITEM                       |   | <- distanceToPeekStart
-     *          |                                                   |   |
-     *          |---------------------------------------------------|  ---  ---
-     *          |__________________SECOND ITEM______________________|        |  <- peekSize
-     *          |===================================================|       _|_
-     *
-     * @param distanceToPeekStart The distance to the start of the peak.
-     * @param linearPart The interpolation factor between the linear and the quadratic amount taken.
-     *                   This factor must be somewhere in [0 , 1]
-     */
-    PiecewiseLinearIndentationFunctor(int maxItemsInStack,
-                                      int peekSize,
-                                      int distanceToPeekStart,
-                                      float linearPart) {
-        super(maxItemsInStack, peekSize, distanceToPeekStart);
-        mBaseValues = new ArrayList<Float>(maxItemsInStack+1);
-        initBaseValues();
-        mLinearPart = linearPart;
-    }
-
-    private void initBaseValues() {
-        int sumOfSquares = getSumOfSquares(mMaxItemsInStack-1);
-        int totalWeight = 0;
-        mBaseValues.add(0.0f);
-        for (int i = 0; i < mMaxItemsInStack - 1; i++) {
-            totalWeight += (mMaxItemsInStack - i - 1) * (mMaxItemsInStack - i - 1);
-            mBaseValues.add((float) totalWeight / sumOfSquares);
-        }
-    }
-
-    /**
-     * Get the sum of squares up to and including n, i.e sum(i * i, 1, n)
-     *
-     * @param n the maximum square to include
-     * @return
-     */
-    private int getSumOfSquares(int n) {
-        return n * (n + 1) * (2 * n + 1) / 6;
-    }
-
-    @Override
-    public float getValue(float itemsBefore) {
-        if (mStackStartsAtPeek) {
-            // We directly start at the stack, so no initial interpolation.
-            itemsBefore++;
-        }
-        if (itemsBefore < 0) {
-            return 0;
-        } else if (itemsBefore >= mMaxItemsInStack) {
-            return mTotalTransitionDistance;
-        }
-        int below = (int) itemsBefore;
-        float partialIn = itemsBefore - below;
-
-        if (below == 0) {
-            return mDistanceToPeekStart * partialIn;
-        } else {
-            float result = mDistanceToPeekStart;
-            float progress = mBaseValues.get(below - 1) * (1 - partialIn)
-                    + mBaseValues.get(below) * partialIn;
-            result += (progress * (1 - mLinearPart)
-                    + (itemsBefore - 1) / (mMaxItemsInStack - 1)  * mLinearPart) * mPeekSize;
-            return result;
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackIndentationFunctor.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackIndentationFunctor.java
deleted file mode 100644
index 034eba6..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackIndentationFunctor.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.stack;
-
-/**
- * A functor which can be queried for offset given the number of items before it.
- */
-public abstract class StackIndentationFunctor {
-
-    protected int mTotalTransitionDistance;
-    protected int mDistanceToPeekStart;
-    protected int mMaxItemsInStack;
-    protected int mPeekSize;
-    protected boolean mStackStartsAtPeek;
-
-    /**
-     * @param maxItemsInStack The maximum number of items which should be visible at the same time,
-     *                        i.e the function returns totalTransitionDistance for the element with
-     *                        index maxItemsInStack
-     * @param peekSize The visual appearance of this is how far the cards in the stack peek
-     *                 out below the top card and it is measured in real pixels.
-     *                 Note that the visual appearance does not necessarily always correspond to
-     *                 the actual visual distance below the top card but is a maximum,
-     *                 achieved when the next card just starts transitioning into the stack and
-     *                 the stack is full.
-     *                 If distanceToPeekStart is 0, we directly start at the peek, otherwise the
-     *                 first element transitions between 0 and distanceToPeekStart.
-     *                 Visualization:
-     *           ---------------------------------------------------   ---
-     *          |                                                   |   |
-     *          |                  FIRST ITEM                       |   | <- distanceToPeekStart
-     *          |                                                   |   |
-     *          |---------------------------------------------------|  ---  ---
-     *          |__________________SECOND ITEM______________________|        |  <- peekSize
-     *          |===================================================|       _|_
-     *
-     * @param distanceToPeekStart The distance to the start of the peak.
-     */
-    StackIndentationFunctor(int maxItemsInStack, int peekSize, int distanceToPeekStart) {
-        mDistanceToPeekStart = distanceToPeekStart;
-        mStackStartsAtPeek = mDistanceToPeekStart == 0;
-        mMaxItemsInStack = maxItemsInStack;
-        mPeekSize = peekSize;
-        updateTotalTransitionDistance();
-
-    }
-
-    private void updateTotalTransitionDistance() {
-        mTotalTransitionDistance = mDistanceToPeekStart + mPeekSize;
-    }
-
-    public void setPeekSize(int mPeekSize) {
-        this.mPeekSize = mPeekSize;
-        updateTotalTransitionDistance();
-    }
-
-    public void setDistanceToPeekStart(int distanceToPeekStart) {
-        mDistanceToPeekStart = distanceToPeekStart;
-        mStackStartsAtPeek = mDistanceToPeekStart == 0;
-        updateTotalTransitionDistance();
-    }
-
-    /**
-     * Gets the offset of this Functor given a the quantity of items before it
-     *
-     * @param itemsBefore how many items are already in the stack before this element
-     * @return the offset
-     */
-    public abstract float getValue(float itemsBefore);
-}
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 c9e4eac..7afc7ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -22,9 +22,10 @@
 import android.view.ViewGroup;
 
 import com.android.systemui.R;
+import com.android.systemui.statusbar.DismissView;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
-import com.android.systemui.statusbar.notification.FakeShadowView;
+import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 
 import java.util.ArrayList;
@@ -40,20 +41,13 @@
 
     private static final String LOG_TAG = "StackScrollAlgorithm";
 
-    private static final int MAX_ITEMS_IN_BOTTOM_STACK = 3;
-
     private int mPaddingBetweenElements;
     private int mIncreasedPaddingBetweenElements;
     private int mCollapsedSize;
-    private int mBottomStackPeekSize;
-    private int mZDistanceBetweenElements;
-    private int mZBasicHeight;
-
-    private StackIndentationFunctor mBottomStackIndentationFunctor;
 
     private StackScrollAlgorithmState mTempAlgorithmState = new StackScrollAlgorithmState();
     private boolean mIsExpanded;
-    private int mBottomStackSlowDownLength;
+    private int mStatusBarHeight;
 
     public StackScrollAlgorithm(Context context) {
         initView(context);
@@ -63,29 +57,14 @@
         initConstants(context);
     }
 
-    public int getBottomStackSlowDownLength() {
-        return mBottomStackSlowDownLength + mPaddingBetweenElements;
-    }
-
     private void initConstants(Context context) {
-        mPaddingBetweenElements = Math.max(1, context.getResources()
-                .getDimensionPixelSize(R.dimen.notification_divider_height));
+        mPaddingBetweenElements = context.getResources().getDimensionPixelSize(
+                R.dimen.notification_divider_height);
         mIncreasedPaddingBetweenElements = context.getResources()
                 .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
         mCollapsedSize = context.getResources()
                 .getDimensionPixelSize(R.dimen.notification_min_height);
-        mBottomStackPeekSize = context.getResources()
-                .getDimensionPixelSize(R.dimen.bottom_stack_peek_amount);
-        mZDistanceBetweenElements = Math.max(1, context.getResources()
-                .getDimensionPixelSize(R.dimen.z_distance_between_notifications));
-        mZBasicHeight = (MAX_ITEMS_IN_BOTTOM_STACK + 1) * mZDistanceBetweenElements;
-        mBottomStackSlowDownLength = context.getResources()
-                .getDimensionPixelSize(R.dimen.bottom_stack_slow_down_length);
-        mBottomStackIndentationFunctor = new PiecewiseLinearIndentationFunctor(
-                MAX_ITEMS_IN_BOTTOM_STACK,
-                mBottomStackPeekSize,
-                getBottomStackSlowDownLength(),
-                0.5f);
+        mStatusBarHeight = context.getResources().getDimensionPixelSize(R.dimen.status_bar_height);
     }
 
     public void getStackScrollState(AmbientState ambientState, StackScrollState resultState) {
@@ -107,7 +86,8 @@
         handleDraggedViews(ambientState, resultState, algorithmState);
         updateDimmedActivatedHideSensitive(ambientState, resultState, algorithmState);
         updateClipping(resultState, algorithmState, ambientState);
-        updateSpeedBumpState(resultState, algorithmState, ambientState.getSpeedBumpIndex());
+        updateSpeedBumpState(resultState, algorithmState, ambientState);
+        updateShelfState(resultState, ambientState);
         getNotificationChildrenStates(resultState, algorithmState);
     }
 
@@ -124,16 +104,22 @@
     }
 
     private void updateSpeedBumpState(StackScrollState resultState,
-            StackScrollAlgorithmState algorithmState, int speedBumpIndex) {
+            StackScrollAlgorithmState algorithmState, AmbientState ambientState) {
         int childCount = algorithmState.visibleChildren.size();
+        int belowSpeedBump = ambientState.getSpeedBumpIndex();
         for (int i = 0; i < childCount; i++) {
             View child = algorithmState.visibleChildren.get(i);
-            StackViewState childViewState = resultState.getViewStateForView(child);
+            ExpandableViewState childViewState = resultState.getViewStateForView(child);
 
             // The speed bump can also be gone, so equality needs to be taken when comparing
             // indices.
-            childViewState.belowSpeedBump = speedBumpIndex != -1 && i >= speedBumpIndex;
+            childViewState.belowSpeedBump = i >= belowSpeedBump;
         }
+
+    }
+    private void updateShelfState(StackScrollState resultState, AmbientState ambientState) {
+        NotificationShelf shelf = ambientState.getShelf();
+        shelf.updateState(resultState, ambientState);
     }
 
     private void updateClipping(StackScrollState resultState,
@@ -144,7 +130,7 @@
         int childCount = algorithmState.visibleChildren.size();
         for (int i = 0; i < childCount; i++) {
             ExpandableView child = algorithmState.visibleChildren.get(i);
-            StackViewState state = resultState.getViewStateForView(child);
+            ExpandableViewState state = resultState.getViewStateForView(child);
             if (!child.mustStayOnScreen()) {
                 previousNotificationEnd = Math.max(drawStart, previousNotificationEnd);
                 previousNotificationStart = Math.max(drawStart, previousNotificationStart);
@@ -154,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;
@@ -195,13 +181,13 @@
         int childCount = algorithmState.visibleChildren.size();
         for (int i = 0; i < childCount; i++) {
             View child = algorithmState.visibleChildren.get(i);
-            StackViewState childViewState = resultState.getViewStateForView(child);
+            ExpandableViewState childViewState = resultState.getViewStateForView(child);
             childViewState.dimmed = dimmed;
             childViewState.dark = dark;
             childViewState.hideSensitive = hideSensitive;
             boolean isActivatedChild = activatedChild == child;
             if (dimmed && isActivatedChild) {
-                childViewState.zTranslation += 2.0f * mZDistanceBetweenElements;
+                childViewState.zTranslation += 2.0f * ambientState.getZDistanceBetweenElements();
             }
         }
     }
@@ -219,7 +205,7 @@
                 if (!draggedViews.contains(nextChild)) {
                     // only if the view is not dragged itself we modify its state to be fully
                     // visible
-                    StackViewState viewState = resultState.getViewStateForView(
+                    ExpandableViewState viewState = resultState.getViewStateForView(
                             nextChild);
                     // The child below the dragged one must be fully visible
                     if (ambientState.isShadeExpanded()) {
@@ -229,7 +215,7 @@
                 }
 
                 // Lets set the alpha to the one it currently has, as its currently being dragged
-                StackViewState viewState = resultState.getViewStateForView(draggedView);
+                ExpandableViewState viewState = resultState.getViewStateForView(draggedView);
                 // The dragged child should keep the set alpha
                 viewState.alpha = draggedView.getAlpha();
             }
@@ -241,8 +227,6 @@
      */
     private void initAlgorithmState(StackScrollState resultState, StackScrollAlgorithmState state,
             AmbientState ambientState) {
-        state.itemsInBottomStack = 0.0f;
-        state.partialInBottom = 0.0f;
         float bottomOverScroll = ambientState.getOverScrollAmount(false /* onTop */);
 
         int scrollY = ambientState.getScrollY();
@@ -263,6 +247,9 @@
         for (int i = 0; i < childCount; i++) {
             ExpandableView v = (ExpandableView) hostView.getChildAt(i);
             if (v.getVisibility() != View.GONE) {
+                if (v == ambientState.getShelf()) {
+                    continue;
+                }
                 notGoneIndex = updateNotGoneIndex(resultState, state, notGoneIndex, v);
                 float increasedPadding = v.getIncreasedPaddingAmount();
                 if (increasedPadding != 0.0f) {
@@ -284,7 +271,7 @@
                     if (row.isSummaryWithChildren() && children != null) {
                         for (ExpandableNotificationRow childRow : children) {
                             if (childRow.getVisibility() != View.GONE) {
-                                StackViewState childState
+                                ExpandableViewState childState
                                         = resultState.getViewStateForView(childRow);
                                 childState.notGoneIndex = notGoneIndex;
                                 notGoneIndex++;
@@ -300,7 +287,7 @@
     private int updateNotGoneIndex(StackScrollState resultState,
             StackScrollAlgorithmState state, int notGoneIndex,
             ExpandableView v) {
-        StackViewState viewState = resultState.getViewStateForView(v);
+        ExpandableViewState viewState = resultState.getViewStateForView(v);
         viewState.notGoneIndex = notGoneIndex;
         state.visibleChildren.add(v);
         notGoneIndex++;
@@ -317,72 +304,39 @@
     private void updatePositionsForState(StackScrollState resultState,
             StackScrollAlgorithmState algorithmState, AmbientState ambientState) {
 
-        // The starting position of the bottom stack peek
-        float bottomPeekStart = ambientState.getInnerHeight() - mBottomStackPeekSize;
-
-        // The position where the bottom stack starts.
-        float bottomStackStart = bottomPeekStart - mBottomStackSlowDownLength;
-
         // The y coordinate of the current child.
         float currentYPosition = -algorithmState.scrollY;
         int childCount = algorithmState.visibleChildren.size();
         for (int i = 0; i < childCount; i++) {
             currentYPosition = updateChild(i, resultState, algorithmState, ambientState,
-                    currentYPosition, bottomStackStart);
+                    currentYPosition);
         }
     }
 
     protected float updateChild(int i, StackScrollState resultState,
             StackScrollAlgorithmState algorithmState, AmbientState ambientState,
-            float currentYPosition, float bottomStackStart) {
+            float currentYPosition) {
         ExpandableView child = algorithmState.visibleChildren.get(i);
-        StackViewState childViewState = resultState.getViewStateForView(child);
-        childViewState.location = StackViewState.LOCATION_UNKNOWN;
+        ExpandableViewState childViewState = resultState.getViewStateForView(child);
+        childViewState.location = ExpandableViewState.LOCATION_UNKNOWN;
         int paddingAfterChild = getPaddingAfterChild(algorithmState, child);
         int childHeight = getMaxAllowedChildHeight(child);
-        int collapsedHeight = child.getCollapsedHeight();
         childViewState.yTranslation = currentYPosition;
-        if (i == 0) {
-            updateFirstChildHeight(child, childViewState, childHeight, ambientState);
-        }
+        boolean isDismissView = child instanceof DismissView;
 
-        // The y position after this element
-        float nextYPosition = currentYPosition + childHeight +
-                paddingAfterChild;
-        if (nextYPosition >= bottomStackStart) {
-            // Case 1:
-            // We are in the bottom stack.
-            if (currentYPosition >= bottomStackStart) {
-                // According to the regular scroll view we are fully translated out of the
-                // bottom of the screen so we are fully in the bottom stack
-                updateStateForChildFullyInBottomStack(algorithmState,
-                        bottomStackStart, childViewState, collapsedHeight, ambientState, child);
-            } else {
-                // According to the regular scroll view we are currently translating out of /
-                // into the bottom of the screen
-                updateStateForChildTransitioningInBottom(algorithmState,
-                        bottomStackStart, child, currentYPosition,
-                        childViewState, childHeight);
-            }
+        childViewState.location = ExpandableViewState.LOCATION_MAIN_AREA;
+        if (isDismissView) {
+            childViewState.yTranslation = Math.min(childViewState.yTranslation,
+                    ambientState.getInnerHeight() - childHeight);
         } else {
-            // Case 2:
-            // We are in the regular scroll area.
-            childViewState.location = StackViewState.LOCATION_MAIN_AREA;
-            clampPositionToBottomStackStart(childViewState, childViewState.height, childHeight,
-                    ambientState);
+            clampPositionToShelf(childViewState, ambientState);
         }
 
-        if (i == 0 && ambientState.getScrollY() <= 0) {
-            // The first card can get into the bottom stack if it's the only one
-            // on the lockscreen which pushes it up. Let's make sure that doesn't happen and
-            // it stays at the top
-            childViewState.yTranslation = Math.max(0, childViewState.yTranslation);
-        }
         currentYPosition = childViewState.yTranslation + childHeight + paddingAfterChild;
         if (currentYPosition <= 0) {
-            childViewState.location = StackViewState.LOCATION_HIDDEN_TOP;
+            childViewState.location = ExpandableViewState.LOCATION_HIDDEN_TOP;
         }
-        if (childViewState.location == StackViewState.LOCATION_UNKNOWN) {
+        if (childViewState.location == ExpandableViewState.LOCATION_UNKNOWN) {
             Log.wtf(LOG_TAG, "Failed to assign location for child " + i);
         }
 
@@ -393,12 +347,7 @@
 
     protected int getPaddingAfterChild(StackScrollAlgorithmState algorithmState,
             ExpandableView child) {
-        Float paddingValue = algorithmState.increasedPaddingMap.get(child);
-        return paddingValue == null
-                ? mPaddingBetweenElements
-                : (int) NotificationUtils.interpolate(mPaddingBetweenElements,
-                        mIncreasedPaddingBetweenElements,
-                        paddingValue);
+        return algorithmState.getPaddingAfterChild(child);
     }
 
     private void updateHeadsUpStates(StackScrollState resultState,
@@ -414,22 +363,26 @@
             if (!row.isHeadsUp()) {
                 break;
             }
-            StackViewState childState = resultState.getViewStateForView(row);
+            ExpandableViewState childState = resultState.getViewStateForView(row);
             if (topHeadsUpEntry == null) {
                 topHeadsUpEntry = row;
-                childState.location = StackViewState.LOCATION_FIRST_HUN;
+                childState.location = ExpandableViewState.LOCATION_FIRST_HUN;
             }
             boolean isTopEntry = topHeadsUpEntry == row;
             float unmodifiedEndLocation = childState.yTranslation + childState.height;
             if (mIsExpanded) {
                 // Ensure that the heads up is always visible even when scrolled off
                 clampHunToTop(ambientState, row, childState);
-                clampHunToMaxTranslation(ambientState, row, childState);
+                if (i == 0) {
+                    // the first hun can't get off screen.
+                    clampHunToMaxTranslation(ambientState, row, childState);
+                }
             }
             if (row.isPinned()) {
                 childState.yTranslation = Math.max(childState.yTranslation, 0);
                 childState.height = Math.max(row.getIntrinsicHeight(), childState.height);
-                StackViewState topState = resultState.getViewStateForView(topHeadsUpEntry);
+                childState.hidden = false;
+                ExpandableViewState topState = resultState.getViewStateForView(topHeadsUpEntry);
                 if (!isTopEntry && (!mIsExpanded
                         || unmodifiedEndLocation < topState.yTranslation + topState.height)) {
                     // Ensure that a headsUp doesn't vertically extend further than the heads-up at
@@ -439,11 +392,14 @@
                             - childState.height;
                 }
             }
+            if (row.isHeadsUpAnimatingAway()) {
+                childState.hidden = false;
+            }
         }
     }
 
     private void clampHunToTop(AmbientState ambientState, ExpandableNotificationRow row,
-            StackViewState childState) {
+            ExpandableViewState childState) {
         float newTranslation = Math.max(ambientState.getTopPadding()
                 + ambientState.getStackTranslation(), childState.yTranslation);
         childState.height = (int) Math.max(childState.height - (newTranslation
@@ -452,7 +408,7 @@
     }
 
     private void clampHunToMaxTranslation(AmbientState ambientState, ExpandableNotificationRow row,
-            StackViewState childState) {
+            ExpandableViewState childState) {
         float newTranslation;
         float bottomPosition = ambientState.getMaxHeadsUpTranslation() - row.getCollapsedHeight();
         newTranslation = Math.min(childState.yTranslation, bottomPosition);
@@ -462,26 +418,23 @@
     }
 
     /**
-     * Clamp the yTranslation of the child down such that its end is at most on the beginning of
-     * the bottom stack.
+     * Clamp the height of the child down such that its end is at most on the beginning of
+     * the shelf.
      *
      * @param childViewState the view state of the child
-     * @param childHeight the height of this child
-     * @param minHeight the minumum Height of the View
+     * @param ambientState the ambient state
      */
-    private void clampPositionToBottomStackStart(StackViewState childViewState,
-            int childHeight, int minHeight, AmbientState ambientState) {
-
-        int bottomStackStart = ambientState.getInnerHeight()
-                - mBottomStackPeekSize - mBottomStackSlowDownLength;
-        int childStart = bottomStackStart - childHeight;
-        if (childStart < childViewState.yTranslation) {
-            float newHeight = bottomStackStart - childViewState.yTranslation;
-            if (newHeight < minHeight) {
-                newHeight = minHeight;
-                childViewState.yTranslation = bottomStackStart - minHeight;
-            }
-            childViewState.height = (int) newHeight;
+    private void clampPositionToShelf(ExpandableViewState childViewState,
+            AmbientState ambientState) {
+        int shelfStart = ambientState.getInnerHeight()
+                - ambientState.getShelf().getIntrinsicHeight();
+        childViewState.yTranslation = Math.min(childViewState.yTranslation, shelfStart);
+        if (childViewState.yTranslation >= shelfStart) {
+            childViewState.hidden = true;
+            childViewState.inShelf = true;
+        }
+        if (!ambientState.isShadeExpanded()) {
+            childViewState.height = (int) (mStatusBarHeight - childViewState.yTranslation);
         }
     }
 
@@ -493,77 +446,6 @@
         return child == null? mCollapsedSize : child.getHeight();
     }
 
-    private void updateStateForChildTransitioningInBottom(StackScrollAlgorithmState algorithmState,
-            float transitioningPositionStart, ExpandableView child, float currentYPosition,
-            StackViewState childViewState, int childHeight) {
-
-        // This is the transitioning element on top of bottom stack, calculate how far we are in.
-        algorithmState.partialInBottom = 1.0f - (
-                (transitioningPositionStart - currentYPosition) / (childHeight +
-                        getPaddingAfterChild(algorithmState, child)));
-
-        // the offset starting at the transitionPosition of the bottom stack
-        float offset = mBottomStackIndentationFunctor.getValue(algorithmState.partialInBottom);
-        algorithmState.itemsInBottomStack += algorithmState.partialInBottom;
-        int newHeight = childHeight;
-        if (childHeight > child.getCollapsedHeight()) {
-            newHeight = (int) Math.max(Math.min(transitioningPositionStart + offset -
-                    getPaddingAfterChild(algorithmState, child) - currentYPosition, childHeight),
-                    child.getCollapsedHeight());
-            childViewState.height = newHeight;
-        }
-        childViewState.yTranslation = transitioningPositionStart + offset - newHeight
-                - getPaddingAfterChild(algorithmState, child);
-        childViewState.location = StackViewState.LOCATION_MAIN_AREA;
-    }
-
-    private void updateStateForChildFullyInBottomStack(StackScrollAlgorithmState algorithmState,
-            float transitioningPositionStart, StackViewState childViewState,
-            int collapsedHeight, AmbientState ambientState, ExpandableView child) {
-        float currentYPosition;
-        algorithmState.itemsInBottomStack += 1.0f;
-        if (algorithmState.itemsInBottomStack < MAX_ITEMS_IN_BOTTOM_STACK) {
-            // We are visually entering the bottom stack
-            currentYPosition = transitioningPositionStart
-                    + mBottomStackIndentationFunctor.getValue(algorithmState.itemsInBottomStack)
-                    - getPaddingAfterChild(algorithmState, child);
-            childViewState.location = StackViewState.LOCATION_BOTTOM_STACK_PEEKING;
-        } else {
-            // we are fully inside the stack
-            if (algorithmState.itemsInBottomStack > MAX_ITEMS_IN_BOTTOM_STACK + 2) {
-                childViewState.hidden = true;
-                childViewState.shadowAlpha = 0.0f;
-            } else if (algorithmState.itemsInBottomStack
-                    > MAX_ITEMS_IN_BOTTOM_STACK + 1) {
-                childViewState.shadowAlpha = 1.0f - algorithmState.partialInBottom;
-            }
-            childViewState.location = StackViewState.LOCATION_BOTTOM_STACK_HIDDEN;
-            currentYPosition = ambientState.getInnerHeight();
-        }
-        childViewState.height = collapsedHeight;
-        childViewState.yTranslation = currentYPosition - collapsedHeight;
-    }
-
-
-    /**
-     * 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 ambientState The ambient state of the algorithm
-     */
-    protected void updateFirstChildHeight(ExpandableView child, StackViewState childViewState,
-                                          int childHeight, AmbientState ambientState) {
-
-            // The starting position of the bottom stack peek
-            int bottomPeekStart = ambientState.getInnerHeight() - mBottomStackPeekSize -
-                    mBottomStackSlowDownLength + ambientState.getScrollY();
-            // Collapse and expand the first child while the shade is being expanded
-        childViewState.height = (int) Math.max(Math.min(bottomPeekStart, (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
@@ -576,37 +458,19 @@
         int childCount = algorithmState.visibleChildren.size();
         float childrenOnTop = 0.0f;
         for (int i = childCount - 1; i >= 0; i--) {
-            updateChildZValue(i, childCount, childrenOnTop,
+            updateChildZValue(i, childrenOnTop,
                     resultState, algorithmState, ambientState);
         }
     }
 
-    protected void updateChildZValue(int i, int childCount, float childrenOnTop,
+    protected void updateChildZValue(int i, float childrenOnTop,
             StackScrollState resultState, StackScrollAlgorithmState algorithmState,
             AmbientState ambientState) {
         ExpandableView child = algorithmState.visibleChildren.get(i);
-        StackViewState childViewState = resultState.getViewStateForView(child);
-        if (i > (childCount - 1 - algorithmState.itemsInBottomStack)) {
-            // We are in the bottom stack
-            float numItemsAbove = i - (childCount - 1 - algorithmState.itemsInBottomStack);
-            float zSubtraction;
-            if (numItemsAbove <= 1.0f) {
-                float factor = 0.2f;
-                // Lets fade in slower to the threshold to make the shadow fade in look nicer
-                if (numItemsAbove <= factor) {
-                    zSubtraction = FakeShadowView.SHADOW_SIBLING_TRESHOLD
-                            * numItemsAbove * (1.0f / factor);
-                } else {
-                    zSubtraction = FakeShadowView.SHADOW_SIBLING_TRESHOLD
-                            + (numItemsAbove - factor) * (1.0f / (1.0f - factor))
-                            * (mZDistanceBetweenElements
-                            - FakeShadowView.SHADOW_SIBLING_TRESHOLD);
-                }
-            } else {
-                zSubtraction = numItemsAbove * mZDistanceBetweenElements;
-            }
-            childViewState.zTranslation = mZBasicHeight - zSubtraction;
-        } else if (child.mustStayOnScreen()
+        ExpandableViewState childViewState = resultState.getViewStateForView(child);
+        int zDistanceBetweenElements = ambientState.getZDistanceBetweenElements();
+        float baseZ = ambientState.getBaseZHeight();
+        if (child.mustStayOnScreen()
                 && childViewState.yTranslation < ambientState.getTopPadding()
                 + ambientState.getStackTranslation()) {
             if (childrenOnTop != 0.0f) {
@@ -616,37 +480,34 @@
                         + ambientState.getStackTranslation() - childViewState.yTranslation;
                 childrenOnTop += Math.min(1.0f, overlap / childViewState.height);
             }
-            childViewState.zTranslation = mZBasicHeight
-                    + childrenOnTop * mZDistanceBetweenElements;
-        } else {
-            childViewState.zTranslation = mZBasicHeight;
-        }
-    }
-
-    private boolean isMaxSizeInitialized(ExpandableView child) {
-        if (child instanceof ExpandableNotificationRow) {
-            ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-            return row.isMaxExpandHeightInitialized();
-        }
-        return child == null || child.getWidth() != 0;
-    }
-
-    private View findFirstVisibleChild(ViewGroup container) {
-        int childCount = container.getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = container.getChildAt(i);
-            if (child.getVisibility() != View.GONE) {
-                return child;
+            childViewState.zTranslation = baseZ
+                    + childrenOnTop * zDistanceBetweenElements;
+        } else if (i == 0 && child.isAboveShelf()) {
+            // In case this is a new view that has never been measured before, we don't want to
+            // elevate if we are currently expanded more then the notification
+            int shelfHeight = ambientState.getShelf().getIntrinsicHeight();
+            float shelfStart = ambientState.getInnerHeight()
+                    - shelfHeight + ambientState.getTopPadding()
+                    + ambientState.getStackTranslation();
+            float notificationEnd = childViewState.yTranslation + child.getPinnedHeadsUpHeight()
+                    + mPaddingBetweenElements;
+            if (shelfStart > notificationEnd) {
+                childViewState.zTranslation = baseZ;
+            } else {
+                float factor = (notificationEnd - shelfStart) / shelfHeight;
+                factor = Math.min(factor, 1.0f);
+                childViewState.zTranslation = baseZ + factor * zDistanceBetweenElements;
             }
+        } else {
+            childViewState.zTranslation = baseZ;
         }
-        return null;
     }
 
     public void setIsExpanded(boolean isExpanded) {
         this.mIsExpanded = isExpanded;
     }
 
-    protected class StackScrollAlgorithmState {
+    public class StackScrollAlgorithmState {
 
         /**
          * The scroll position of the algorithm
@@ -654,16 +515,6 @@
         public int scrollY;
 
         /**
-         * The quantity of items which are in the bottom stack.
-         */
-        public float itemsInBottomStack;
-
-        /**
-         * how far in is the element currently transitioning into the bottom stack
-         */
-        public float partialInBottom;
-
-        /**
          * The children from the host view which are not gone.
          */
         public final ArrayList<ExpandableView> visibleChildren = new ArrayList<ExpandableView>();
@@ -673,6 +524,15 @@
          * no increased padding, a value of 1 means full padding.
          */
         public final HashMap<ExpandableView, Float> increasedPaddingMap = new HashMap<>();
+
+        public int getPaddingAfterChild(ExpandableView child) {
+            Float paddingValue = increasedPaddingMap.get(child);
+            return paddingValue == null
+                    ? mPaddingBetweenElements
+                    : (int) NotificationUtils.interpolate(mPaddingBetweenElements,
+                            mIncreasedPaddingBetweenElements,
+                            paddingValue);
+        }
     }
 
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index 8f0cd8e..e3c746b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -21,8 +21,6 @@
 import android.view.ViewGroup;
 
 import com.android.systemui.R;
-import com.android.systemui.statusbar.DismissView;
-import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
 
@@ -38,14 +36,11 @@
     private static final String CHILD_NOT_FOUND_TAG = "StackScrollStateNoSuchChild";
 
     private final ViewGroup mHostView;
-    private WeakHashMap<ExpandableView, StackViewState> mStateMap;
-    private final int mClearAllTopPadding;
+    private WeakHashMap<ExpandableView, ExpandableViewState> mStateMap;
 
     public StackScrollState(ViewGroup hostView) {
         mHostView = hostView;
         mStateMap = new WeakHashMap<>();
-        mClearAllTopPadding = hostView.getContext().getResources().getDimensionPixelSize(
-                R.dimen.clear_all_padding_top);
     }
 
     public ViewGroup getHostView() {
@@ -73,9 +68,9 @@
     }
 
     private void resetViewState(ExpandableView view) {
-        StackViewState viewState = mStateMap.get(view);
+        ExpandableViewState viewState = mStateMap.get(view);
         if (viewState == null) {
-            viewState = new StackViewState();
+            viewState = view.createNewViewState(this);
             mStateMap.put(view, viewState);
         }
         // initialize with the default values of the view
@@ -84,10 +79,14 @@
         viewState.alpha = 1f;
         viewState.shadowAlpha = 1f;
         viewState.notGoneIndex = -1;
+        viewState.xTranslation = view.getTranslationX();
         viewState.hidden = false;
+        viewState.scaleX = view.getScaleX();
+        viewState.scaleY = view.getScaleY();
+        viewState.inShelf = false;
     }
 
-    public StackViewState getViewStateForView(View requestedView) {
+    public ExpandableViewState getViewStateForView(View requestedView) {
         return mStateMap.get(requestedView);
     }
 
@@ -103,130 +102,16 @@
         int numChildren = mHostView.getChildCount();
         for (int i = 0; i < numChildren; i++) {
             ExpandableView child = (ExpandableView) mHostView.getChildAt(i);
-            StackViewState state = mStateMap.get(child);
-            if (!applyState(child, state)) {
+            ExpandableViewState state = mStateMap.get(child);
+            if (state == null) {
+                Log.wtf(CHILD_NOT_FOUND_TAG, "No child state was found when applying this state " +
+                        "to the hostView");
                 continue;
             }
-            if (child instanceof DismissView) {
-                DismissView dismissView = (DismissView) child;
-                boolean visible = state.clipTopAmount < mClearAllTopPadding;
-                dismissView.performVisibilityAnimation(visible && !dismissView.willBeGone());
-            } else if (child instanceof EmptyShadeView) {
-                EmptyShadeView emptyShadeView = (EmptyShadeView) child;
-                boolean visible = state.clipTopAmount <= 0;
-                emptyShadeView.performVisibilityAnimation(
-                        visible && !emptyShadeView.willBeGone());
+            if (state.gone) {
+                continue;
             }
-        }
-    }
-
-    /**
-     * Applies a  {@link StackViewState} to an  {@link ExpandableView}.
-     *
-     * @return whether the state was applied correctly
-     */
-    public boolean applyState(ExpandableView view, StackViewState state) {
-        if (state == null) {
-            Log.wtf(CHILD_NOT_FOUND_TAG, "No child state was found when applying this state " +
-                    "to the hostView");
-            return false;
-        }
-        if (state.gone) {
-            return false;
-        }
-        applyViewState(view, state);
-
-        int height = view.getActualHeight();
-        int newHeight = state.height;
-
-        // apply height
-        if (height != newHeight) {
-            view.setActualHeight(newHeight, false /* notifyListeners */);
-        }
-
-        float shadowAlpha = view.getShadowAlpha();
-        float newShadowAlpha = state.shadowAlpha;
-
-        // apply shadowAlpha
-        if (shadowAlpha != newShadowAlpha) {
-            view.setShadowAlpha(newShadowAlpha);
-        }
-
-        // apply dimming
-        view.setDimmed(state.dimmed, false /* animate */);
-
-        // apply hiding sensitive
-        view.setHideSensitive(
-                state.hideSensitive, false /* animated */, 0 /* delay */, 0 /* duration */);
-
-        // apply speed bump state
-        view.setBelowSpeedBump(state.belowSpeedBump);
-
-        // apply dark
-        view.setDark(state.dark, false /* animate */, 0 /* delay */);
-
-        // apply clipping
-        float oldClipTopAmount = view.getClipTopAmount();
-        if (oldClipTopAmount != state.clipTopAmount) {
-            view.setClipTopAmount(state.clipTopAmount);
-        }
-        if (view instanceof ExpandableNotificationRow) {
-            ExpandableNotificationRow row = (ExpandableNotificationRow) view;
-            if (state.isBottomClipped) {
-                row.setClipToActualHeight(true);
-            }
-            row.applyChildrenState(this);
-        }
-        return true;
-    }
-
-    /**
-     * Applies a  {@link ViewState} to a normal view.
-     */
-    public void applyViewState(View view, ViewState state) {
-        float alpha = view.getAlpha();
-        float yTranslation = view.getTranslationY();
-        float xTranslation = view.getTranslationX();
-        float zTranslation = view.getTranslationZ();
-        float newAlpha = state.alpha;
-        float newYTranslation = state.yTranslation;
-        float newZTranslation = state.zTranslation;
-        boolean becomesInvisible = newAlpha == 0.0f || state.hidden;
-        if (alpha != newAlpha && xTranslation == 0) {
-            // apply layer type
-            boolean becomesFullyVisible = newAlpha == 1.0f;
-            boolean newLayerTypeIsHardware = !becomesInvisible && !becomesFullyVisible
-                    && view.hasOverlappingRendering();
-            int layerType = view.getLayerType();
-            int newLayerType = newLayerTypeIsHardware
-                    ? View.LAYER_TYPE_HARDWARE
-                    : View.LAYER_TYPE_NONE;
-            if (layerType != newLayerType) {
-                view.setLayerType(newLayerType, null);
-            }
-
-            // apply alpha
-            view.setAlpha(newAlpha);
-        }
-
-        // apply visibility
-        int oldVisibility = view.getVisibility();
-        int newVisibility = becomesInvisible ? View.INVISIBLE : View.VISIBLE;
-        if (newVisibility != oldVisibility) {
-            if (!(view instanceof ExpandableView) || !((ExpandableView) view).willBeGone()) {
-                // We don't want views to change visibility when they are animating to GONE
-                view.setVisibility(newVisibility);
-            }
-        }
-
-        // apply yTranslation
-        if (yTranslation != newYTranslation) {
-            view.setTranslationY(newYTranslation);
-        }
-
-        // apply zTranslation
-        if (zTranslation != newZTranslation) {
-            view.setTranslationZ(newZTranslation);
+            state.applyToView(child);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index 3804b42..1f29b4f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -18,9 +18,8 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
 import android.animation.ValueAnimator;
+import android.util.Property;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.Interpolator;
@@ -29,7 +28,7 @@
 import com.android.systemui.R;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.NotificationShelf;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -54,28 +53,10 @@
     public static final int DELAY_EFFECT_MAX_INDEX_DIFFERENCE = 2;
     public static final int ANIMATION_DELAY_HEADS_UP = 120;
 
-    private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag;
-    private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag;
-    private static final int TAG_ANIMATOR_ALPHA = R.id.alpha_animator_tag;
-    private static final int TAG_ANIMATOR_HEIGHT = R.id.height_animator_tag;
-    private static final int TAG_ANIMATOR_TOP_INSET = R.id.top_inset_animator_tag;
-    private static final int TAG_ANIMATOR_SHADOW_ALPHA = R.id.shadow_alpha_animator_tag;
-    private static final int TAG_END_TRANSLATION_Y = R.id.translation_y_animator_end_value_tag;
-    private static final int TAG_END_TRANSLATION_Z = R.id.translation_z_animator_end_value_tag;
-    private static final int TAG_END_ALPHA = R.id.alpha_animator_end_value_tag;
-    private static final int TAG_END_HEIGHT = R.id.height_animator_end_value_tag;
-    private static final int TAG_END_TOP_INSET = R.id.top_inset_animator_end_value_tag;
-    private static final int TAG_END_SHADOW_ALPHA = R.id.shadow_alpha_animator_end_value_tag;
-    private static final int TAG_START_TRANSLATION_Y = R.id.translation_y_animator_start_value_tag;
-    private static final int TAG_START_TRANSLATION_Z = R.id.translation_z_animator_start_value_tag;
-    private static final int TAG_START_ALPHA = R.id.alpha_animator_start_value_tag;
-    private static final int TAG_START_HEIGHT = R.id.height_animator_start_value_tag;
-    private static final int TAG_START_TOP_INSET = R.id.top_inset_animator_start_value_tag;
-    private static final int TAG_START_SHADOW_ALPHA = R.id.shadow_alpha_animator_start_value_tag;
-
     private final Interpolator mHeadsUpAppearInterpolator;
     private final int mGoToFullShadeAppearingTranslation;
-    private final StackViewState mTmpState = new StackViewState();
+    private final ExpandableViewState mTmpState = new ExpandableViewState();
+    private final AnimationProperties mAnimationProperties;
     public NotificationStackScrollLayout mHostLayout;
     private ArrayList<NotificationStackScrollLayout.AnimationEvent> mNewEvents =
             new ArrayList<>();
@@ -95,6 +76,7 @@
     private int mHeadsUpAppearHeightBottom;
     private boolean mShadeExpanded;
     private ArrayList<View> mChildrenToClearFromOverlay = new ArrayList<>();
+    private NotificationShelf mShelf;
 
     public StackStateAnimator(NotificationStackScrollLayout hostLayout) {
         mHostLayout = hostLayout;
@@ -102,6 +84,30 @@
                 hostLayout.getContext().getResources().getDimensionPixelSize(
                         R.dimen.go_to_full_shade_appearing_translation);
         mHeadsUpAppearInterpolator = new HeadsUpAppearInterpolator();
+        mAnimationProperties = new AnimationProperties() {
+            @Override
+            public AnimationFilter getAnimationFilter() {
+                return mAnimationFilter;
+            }
+
+            @Override
+            public AnimatorListenerAdapter getAnimationFinishListener() {
+                return getGlobalAnimationFinishedListener();
+            }
+
+            @Override
+            public boolean wasAdded(View view) {
+                return mNewAddChildren.contains(view);
+            }
+
+            @Override
+            public Interpolator getCustomInterpolator(View child, Property property) {
+                if (mHeadsUpAppearChildren.contains(child) && View.TRANSLATION_Y.equals(property)) {
+                    return mHeadsUpAppearInterpolator;
+                }
+                return null;
+            }
+        };
     }
 
     public boolean isRunning() {
@@ -122,13 +128,14 @@
         for (int i = 0; i < childCount; i++) {
             final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
 
-            StackViewState viewState = finalState.getViewStateForView(child);
+            ExpandableViewState viewState = finalState.getViewStateForView(child);
             if (viewState == null || child.getVisibility() == View.GONE
                     || applyWithoutAnimation(child, viewState, finalState)) {
                 continue;
             }
 
-            startStackAnimations(child, viewState, finalState, i, -1 /* fixedDelay */);
+            initAnimationProperties(finalState, child, viewState);
+            viewState.animateTo(child, mAnimationProperties);
         }
         if (!isRunning()) {
             // no child has preformed any animation, lets finish
@@ -140,17 +147,47 @@
         mNewAddChildren.clear();
     }
 
+    private void initAnimationProperties(StackScrollState finalState, ExpandableView child,
+            ExpandableViewState viewState) {
+        boolean wasAdded = mAnimationProperties.wasAdded(child);
+        mAnimationProperties.duration = mCurrentLength;
+        adaptDurationWhenGoingToFullShade(child, viewState, wasAdded);
+        mAnimationProperties.delay = 0;
+        if (wasAdded || mAnimationFilter.hasDelays
+                        && (viewState.yTranslation != child.getTranslationY()
+                        || viewState.zTranslation != child.getTranslationZ()
+                        || viewState.alpha != child.getAlpha()
+                        || viewState.height != child.getActualHeight()
+                        || viewState.clipTopAmount != child.getClipTopAmount()
+                        || viewState.dark != child.isDark()
+                        || viewState.shadowAlpha != child.getShadowAlpha())) {
+            mAnimationProperties.delay = mCurrentAdditionalDelay
+                    + calculateChildAnimationDelay(viewState, finalState);
+        }
+    }
+
+    private void adaptDurationWhenGoingToFullShade(ExpandableView child,
+            ExpandableViewState viewState, boolean wasAdded) {
+        if (wasAdded && mAnimationFilter.hasGoToFullShadeEvent) {
+            child.setTranslationY(child.getTranslationY() + mGoToFullShadeAppearingTranslation);
+            float longerDurationFactor = viewState.notGoneIndex - mCurrentLastNotAddedIndex;
+            longerDurationFactor = (float) Math.pow(longerDurationFactor, 0.7f);
+            mAnimationProperties.duration = ANIMATION_DURATION_APPEAR_DISAPPEAR + 50 +
+                    (long) (100 * longerDurationFactor);
+        }
+    }
+
     /**
      * Determines if a view should not perform an animation and applies it directly.
      *
      * @return true if no animation should be performed
      */
-    private boolean applyWithoutAnimation(ExpandableView child, StackViewState viewState,
+    private boolean applyWithoutAnimation(ExpandableView child, ExpandableViewState viewState,
             StackScrollState finalState) {
         if (mShadeExpanded) {
             return false;
         }
-        if (getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y) != null) {
+        if (ViewState.isAnimatingY(child)) {
             // A Y translation animation is running
             return false;
         }
@@ -162,7 +199,7 @@
             // This is another headsUp which might move. Let's animate!
             return false;
         }
-        finalState.applyState(child, viewState);
+        viewState.applyToView(child);
         return true;
     }
 
@@ -171,7 +208,7 @@
         for (int i = childCount - 1; i >= 0; i--) {
             final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
 
-            StackViewState viewState = finalState.getViewStateForView(child);
+            ExpandableViewState viewState = finalState.getViewStateForView(child);
             if (viewState == null || child.getVisibility() == View.GONE) {
                 continue;
             }
@@ -182,144 +219,7 @@
         return -1;
     }
 
-
-    /**
-     * Start an animation to the given  {@link StackViewState}.
-     *
-     * @param child the child to start the animation on
-     * @param viewState the {@link StackViewState} of the view to animate to
-     * @param finalState the final state after the animation
-     * @param i the index of the view; only relevant if the view is the speed bump and is
-     *          ignored otherwise
-     * @param fixedDelay a fixed delay if desired or -1 if the delay should be calculated
-     */
-    public void startStackAnimations(final ExpandableView child, StackViewState viewState,
-            StackScrollState finalState, int i, long fixedDelay) {
-        boolean wasAdded = mNewAddChildren.contains(child);
-        long duration = mCurrentLength;
-        if (wasAdded && mAnimationFilter.hasGoToFullShadeEvent) {
-            child.setTranslationY(child.getTranslationY() + mGoToFullShadeAppearingTranslation);
-            float longerDurationFactor = viewState.notGoneIndex - mCurrentLastNotAddedIndex;
-            longerDurationFactor = (float) Math.pow(longerDurationFactor, 0.7f);
-            duration = ANIMATION_DURATION_APPEAR_DISAPPEAR + 50 +
-                    (long) (100 * longerDurationFactor);
-        }
-        boolean yTranslationChanging = child.getTranslationY() != viewState.yTranslation;
-        boolean zTranslationChanging = child.getTranslationZ() != viewState.zTranslation;
-        boolean alphaChanging = viewState.alpha != child.getAlpha();
-        boolean heightChanging = viewState.height != child.getActualHeight();
-        boolean shadowAlphaChanging = viewState.shadowAlpha != child.getShadowAlpha();
-        boolean darkChanging = viewState.dark != child.isDark();
-        boolean topInsetChanging = viewState.clipTopAmount != child.getClipTopAmount();
-        boolean hasDelays = mAnimationFilter.hasDelays;
-        boolean isDelayRelevant = yTranslationChanging || zTranslationChanging || alphaChanging
-                || heightChanging || topInsetChanging || darkChanging || shadowAlphaChanging;
-        long delay = 0;
-        if (fixedDelay != -1) {
-            delay = fixedDelay;
-        } else if (hasDelays && isDelayRelevant || wasAdded) {
-            delay = mCurrentAdditionalDelay + calculateChildAnimationDelay(viewState, finalState);
-        }
-
-        startViewAnimations(child, viewState, delay, duration);
-
-        // start height animation
-        if (heightChanging) {
-            startHeightAnimation(child, viewState, duration, delay);
-        }  else {
-            abortAnimation(child, TAG_ANIMATOR_HEIGHT);
-        }
-
-        // start shadow alpha animation
-        if (shadowAlphaChanging) {
-            startShadowAlphaAnimation(child, viewState, duration, delay);
-        } else {
-            abortAnimation(child, TAG_ANIMATOR_SHADOW_ALPHA);
-        }
-
-        // start top inset animation
-        if (topInsetChanging) {
-            startInsetAnimation(child, viewState, duration, delay);
-        } else {
-            abortAnimation(child, TAG_ANIMATOR_TOP_INSET);
-        }
-
-        // start dimmed animation
-        child.setDimmed(viewState.dimmed, mAnimationFilter.animateDimmed);
-
-        // apply speed bump state
-        child.setBelowSpeedBump(viewState.belowSpeedBump);
-
-        // start hiding sensitive animation
-        child.setHideSensitive(viewState.hideSensitive, mAnimationFilter.animateHideSensitive,
-                delay, duration);
-
-        // start dark animation
-        child.setDark(viewState.dark, mAnimationFilter.animateDark, delay);
-
-        if (wasAdded) {
-            child.performAddAnimation(delay, mCurrentLength);
-        }
-        if (child instanceof ExpandableNotificationRow) {
-            ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-            row.startChildAnimation(finalState, this, delay, duration);
-        }
-    }
-
-    /**
-     * Start an animation to a new {@link ViewState}.
-     *
-     * @param child the child to start the animation on
-     * @param viewState the  {@link StackViewState} of the view to animate to
-     * @param delay a fixed delay
-     * @param duration the duration of the animation
-     */
-    public void startViewAnimations(View child, ViewState viewState, long delay, long duration) {
-        boolean wasVisible = child.getVisibility() == View.VISIBLE;
-        final float alpha = viewState.alpha;
-        if (!wasVisible && (alpha != 0 || child.getAlpha() != 0)
-                && !viewState.gone && !viewState.hidden) {
-            child.setVisibility(View.VISIBLE);
-        }
-        boolean yTranslationChanging = child.getTranslationY() != viewState.yTranslation;
-        boolean zTranslationChanging = child.getTranslationZ() != viewState.zTranslation;
-        float childAlpha = child.getAlpha();
-        boolean alphaChanging = viewState.alpha != childAlpha;
-        if (child instanceof ExpandableView) {
-            // We don't want views to change visibility when they are animating to GONE
-            alphaChanging &= !((ExpandableView) child).willBeGone();
-        }
-
-        // start translationY animation
-        if (yTranslationChanging) {
-            startYTranslationAnimation(child, viewState, duration, delay);
-        } else {
-            abortAnimation(child, TAG_ANIMATOR_TRANSLATION_Y);
-        }
-
-        // start translationZ animation
-        if (zTranslationChanging) {
-            startZTranslationAnimation(child, viewState, duration, delay);
-        } else {
-            abortAnimation(child, TAG_ANIMATOR_TRANSLATION_Z);
-        }
-
-        // start alpha animation
-        if (alphaChanging && child.getTranslationX() == 0) {
-            startAlphaAnimation(child, viewState, duration, delay);
-        }  else {
-            abortAnimation(child, TAG_ANIMATOR_ALPHA);
-        }
-    }
-
-    private void abortAnimation(View child, int animatorTag) {
-        Animator previousAnimator = getChildTag(child, animatorTag);
-        if (previousAnimator != null) {
-            previousAnimator.cancel();
-        }
-    }
-
-    private long calculateChildAnimationDelay(StackViewState viewState,
+    private long calculateChildAnimationDelay(ExpandableViewState viewState,
             StackScrollState finalState) {
         if (mAnimationFilter.hasDarkEvent) {
             return calculateDelayDark(viewState);
@@ -374,7 +274,7 @@
         return minDelay;
     }
 
-    private long calculateDelayDark(StackViewState viewState) {
+    private long calculateDelayDark(ExpandableViewState viewState) {
         int referenceIndex;
         if (mAnimationFilter.darkAnimationOriginIndex ==
                 NotificationStackScrollLayout.AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE) {
@@ -388,400 +288,19 @@
         return Math.abs(referenceIndex - viewState.notGoneIndex) * ANIMATION_DELAY_PER_ELEMENT_DARK;
     }
 
-    private long calculateDelayGoToFullShade(StackViewState viewState) {
+    private long calculateDelayGoToFullShade(ExpandableViewState viewState) {
+        int shelfIndex = mShelf.getNotGoneIndex();
         float index = viewState.notGoneIndex;
+        long result = 0;
+        if (index > shelfIndex) {
+            float diff = index - shelfIndex;
+            diff = (float) Math.pow(diff, 0.7f);
+            result += (long) (diff * ANIMATION_DELAY_PER_ELEMENT_GO_TO_FULL_SHADE * 0.25);
+            index = shelfIndex;
+        }
         index = (float) Math.pow(index, 0.7f);
-        return (long) (index * ANIMATION_DELAY_PER_ELEMENT_GO_TO_FULL_SHADE);
-    }
-
-    private void startShadowAlphaAnimation(final ExpandableView child,
-            StackViewState viewState, long duration, long delay) {
-        Float previousStartValue = getChildTag(child, TAG_START_SHADOW_ALPHA);
-        Float previousEndValue = getChildTag(child, TAG_END_SHADOW_ALPHA);
-        float newEndValue = viewState.shadowAlpha;
-        if (previousEndValue != null && previousEndValue == newEndValue) {
-            return;
-        }
-        ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_SHADOW_ALPHA);
-        if (!mAnimationFilter.animateShadowAlpha) {
-            // just a local update was performed
-            if (previousAnimator != null) {
-                // we need to increase all animation keyframes of the previous animator by the
-                // relative change to the end value
-                PropertyValuesHolder[] values = previousAnimator.getValues();
-                float relativeDiff = newEndValue - previousEndValue;
-                float newStartValue = previousStartValue + relativeDiff;
-                values[0].setFloatValues(newStartValue, newEndValue);
-                child.setTag(TAG_START_SHADOW_ALPHA, newStartValue);
-                child.setTag(TAG_END_SHADOW_ALPHA, newEndValue);
-                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
-                return;
-            } else {
-                // no new animation needed, let's just apply the value
-                child.setShadowAlpha(newEndValue);
-                return;
-            }
-        }
-
-        ValueAnimator animator = ValueAnimator.ofFloat(child.getShadowAlpha(), newEndValue);
-        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                child.setShadowAlpha((float) animation.getAnimatedValue());
-            }
-        });
-        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
-        long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
-        animator.setDuration(newDuration);
-        if (delay > 0 && (previousAnimator == null
-                || previousAnimator.getAnimatedFraction() == 0)) {
-            animator.setStartDelay(delay);
-        }
-        animator.addListener(getGlobalAnimationFinishedListener());
-        // remove the tag when the animation is finished
-        animator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                child.setTag(TAG_ANIMATOR_SHADOW_ALPHA, null);
-                child.setTag(TAG_START_SHADOW_ALPHA, null);
-                child.setTag(TAG_END_SHADOW_ALPHA, null);
-            }
-        });
-        startAnimator(animator);
-        child.setTag(TAG_ANIMATOR_SHADOW_ALPHA, animator);
-        child.setTag(TAG_START_SHADOW_ALPHA, child.getShadowAlpha());
-        child.setTag(TAG_END_SHADOW_ALPHA, newEndValue);
-    }
-
-    private void startHeightAnimation(final ExpandableView child,
-            StackViewState viewState, long duration, long delay) {
-        Integer previousStartValue = getChildTag(child, TAG_START_HEIGHT);
-        Integer previousEndValue = getChildTag(child, TAG_END_HEIGHT);
-        int newEndValue = viewState.height;
-        if (previousEndValue != null && previousEndValue == newEndValue) {
-            return;
-        }
-        ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_HEIGHT);
-        if (!mAnimationFilter.animateHeight) {
-            // just a local update was performed
-            if (previousAnimator != null) {
-                // we need to increase all animation keyframes of the previous animator by the
-                // relative change to the end value
-                PropertyValuesHolder[] values = previousAnimator.getValues();
-                int relativeDiff = newEndValue - previousEndValue;
-                int newStartValue = previousStartValue + relativeDiff;
-                values[0].setIntValues(newStartValue, newEndValue);
-                child.setTag(TAG_START_HEIGHT, newStartValue);
-                child.setTag(TAG_END_HEIGHT, newEndValue);
-                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
-                return;
-            } else {
-                // no new animation needed, let's just apply the value
-                child.setActualHeight(newEndValue, false);
-                return;
-            }
-        }
-
-        ValueAnimator animator = ValueAnimator.ofInt(child.getActualHeight(), newEndValue);
-        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                child.setActualHeight((int) animation.getAnimatedValue(),
-                        false /* notifyListeners */);
-            }
-        });
-        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
-        long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
-        animator.setDuration(newDuration);
-        if (delay > 0 && (previousAnimator == null
-                || previousAnimator.getAnimatedFraction() == 0)) {
-            animator.setStartDelay(delay);
-        }
-        animator.addListener(getGlobalAnimationFinishedListener());
-        // remove the tag when the animation is finished
-        animator.addListener(new AnimatorListenerAdapter() {
-            boolean mWasCancelled;
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                child.setTag(TAG_ANIMATOR_HEIGHT, null);
-                child.setTag(TAG_START_HEIGHT, null);
-                child.setTag(TAG_END_HEIGHT, null);
-                child.setActualHeightAnimating(false);
-                if (!mWasCancelled && child instanceof ExpandableNotificationRow) {
-                    ((ExpandableNotificationRow) child).setGroupExpansionChanging(
-                            false /* isExpansionChanging */);
-                }
-            }
-
-            @Override
-            public void onAnimationStart(Animator animation) {
-                mWasCancelled = false;
-            }
-
-            @Override
-            public void onAnimationCancel(Animator animation) {
-                mWasCancelled = true;
-            }
-        });
-        startAnimator(animator);
-        child.setTag(TAG_ANIMATOR_HEIGHT, animator);
-        child.setTag(TAG_START_HEIGHT, child.getActualHeight());
-        child.setTag(TAG_END_HEIGHT, newEndValue);
-        child.setActualHeightAnimating(true);
-    }
-
-    private void startInsetAnimation(final ExpandableView child,
-            StackViewState viewState, long duration, long delay) {
-        Integer previousStartValue = getChildTag(child, TAG_START_TOP_INSET);
-        Integer previousEndValue = getChildTag(child, TAG_END_TOP_INSET);
-        int newEndValue = viewState.clipTopAmount;
-        if (previousEndValue != null && previousEndValue == newEndValue) {
-            return;
-        }
-        ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TOP_INSET);
-        if (!mAnimationFilter.animateTopInset) {
-            // just a local update was performed
-            if (previousAnimator != null) {
-                // we need to increase all animation keyframes of the previous animator by the
-                // relative change to the end value
-                PropertyValuesHolder[] values = previousAnimator.getValues();
-                int relativeDiff = newEndValue - previousEndValue;
-                int newStartValue = previousStartValue + relativeDiff;
-                values[0].setIntValues(newStartValue, newEndValue);
-                child.setTag(TAG_START_TOP_INSET, newStartValue);
-                child.setTag(TAG_END_TOP_INSET, newEndValue);
-                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
-                return;
-            } else {
-                // no new animation needed, let's just apply the value
-                child.setClipTopAmount(newEndValue);
-                return;
-            }
-        }
-
-        ValueAnimator animator = ValueAnimator.ofInt(child.getClipTopAmount(), newEndValue);
-        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                child.setClipTopAmount((int) animation.getAnimatedValue());
-            }
-        });
-        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
-        long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
-        animator.setDuration(newDuration);
-        if (delay > 0 && (previousAnimator == null
-                || previousAnimator.getAnimatedFraction() == 0)) {
-            animator.setStartDelay(delay);
-        }
-        animator.addListener(getGlobalAnimationFinishedListener());
-        // remove the tag when the animation is finished
-        animator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                child.setTag(TAG_ANIMATOR_TOP_INSET, null);
-                child.setTag(TAG_START_TOP_INSET, null);
-                child.setTag(TAG_END_TOP_INSET, null);
-            }
-        });
-        startAnimator(animator);
-        child.setTag(TAG_ANIMATOR_TOP_INSET, animator);
-        child.setTag(TAG_START_TOP_INSET, child.getClipTopAmount());
-        child.setTag(TAG_END_TOP_INSET, newEndValue);
-    }
-
-    private void startAlphaAnimation(final View child,
-            final ViewState viewState, long duration, long delay) {
-        Float previousStartValue = getChildTag(child,TAG_START_ALPHA);
-        Float previousEndValue = getChildTag(child,TAG_END_ALPHA);
-        final float newEndValue = viewState.alpha;
-        if (previousEndValue != null && previousEndValue == newEndValue) {
-            return;
-        }
-        ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_ALPHA);
-        if (!mAnimationFilter.animateAlpha) {
-            // just a local update was performed
-            if (previousAnimator != null) {
-                // we need to increase all animation keyframes of the previous animator by the
-                // relative change to the end value
-                PropertyValuesHolder[] values = previousAnimator.getValues();
-                float relativeDiff = newEndValue - previousEndValue;
-                float newStartValue = previousStartValue + relativeDiff;
-                values[0].setFloatValues(newStartValue, newEndValue);
-                child.setTag(TAG_START_ALPHA, newStartValue);
-                child.setTag(TAG_END_ALPHA, newEndValue);
-                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
-                return;
-            } else {
-                // no new animation needed, let's just apply the value
-                child.setAlpha(newEndValue);
-                if (newEndValue == 0) {
-                    child.setVisibility(View.INVISIBLE);
-                }
-            }
-        }
-
-        ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.ALPHA,
-                child.getAlpha(), newEndValue);
-        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
-        // Handle layer type
-        child.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-        animator.addListener(new AnimatorListenerAdapter() {
-            public boolean mWasCancelled;
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                child.setLayerType(View.LAYER_TYPE_NONE, null);
-                if (newEndValue == 0 && !mWasCancelled) {
-                    child.setVisibility(View.INVISIBLE);
-                }
-                // remove the tag when the animation is finished
-                child.setTag(TAG_ANIMATOR_ALPHA, null);
-                child.setTag(TAG_START_ALPHA, null);
-                child.setTag(TAG_END_ALPHA, null);
-            }
-
-            @Override
-            public void onAnimationCancel(Animator animation) {
-                mWasCancelled = true;
-            }
-
-            @Override
-            public void onAnimationStart(Animator animation) {
-                mWasCancelled = false;
-            }
-        });
-        long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
-        animator.setDuration(newDuration);
-        if (delay > 0 && (previousAnimator == null
-                || previousAnimator.getAnimatedFraction() == 0)) {
-            animator.setStartDelay(delay);
-        }
-        animator.addListener(getGlobalAnimationFinishedListener());
-
-        startAnimator(animator);
-        child.setTag(TAG_ANIMATOR_ALPHA, animator);
-        child.setTag(TAG_START_ALPHA, child.getAlpha());
-        child.setTag(TAG_END_ALPHA, newEndValue);
-    }
-
-    private void startZTranslationAnimation(final View child,
-            final ViewState viewState, long duration, long delay) {
-        Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Z);
-        Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Z);
-        float newEndValue = viewState.zTranslation;
-        if (previousEndValue != null && previousEndValue == newEndValue) {
-            return;
-        }
-        ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Z);
-        if (!mAnimationFilter.animateZ) {
-            // just a local update was performed
-            if (previousAnimator != null) {
-                // we need to increase all animation keyframes of the previous animator by the
-                // relative change to the end value
-                PropertyValuesHolder[] values = previousAnimator.getValues();
-                float relativeDiff = newEndValue - previousEndValue;
-                float newStartValue = previousStartValue + relativeDiff;
-                values[0].setFloatValues(newStartValue, newEndValue);
-                child.setTag(TAG_START_TRANSLATION_Z, newStartValue);
-                child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
-                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
-                return;
-            } else {
-                // no new animation needed, let's just apply the value
-                child.setTranslationZ(newEndValue);
-            }
-        }
-
-        ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Z,
-                child.getTranslationZ(), newEndValue);
-        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
-        long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
-        animator.setDuration(newDuration);
-        if (delay > 0 && (previousAnimator == null
-                || previousAnimator.getAnimatedFraction() == 0)) {
-            animator.setStartDelay(delay);
-        }
-        animator.addListener(getGlobalAnimationFinishedListener());
-        // remove the tag when the animation is finished
-        animator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                child.setTag(TAG_ANIMATOR_TRANSLATION_Z, null);
-                child.setTag(TAG_START_TRANSLATION_Z, null);
-                child.setTag(TAG_END_TRANSLATION_Z, null);
-            }
-        });
-        startAnimator(animator);
-        child.setTag(TAG_ANIMATOR_TRANSLATION_Z, animator);
-        child.setTag(TAG_START_TRANSLATION_Z, child.getTranslationZ());
-        child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
-    }
-
-    private void startYTranslationAnimation(final View child,
-            ViewState viewState, long duration, long delay) {
-        Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Y);
-        Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Y);
-        float newEndValue = viewState.yTranslation;
-        if (previousEndValue != null && previousEndValue == newEndValue) {
-            return;
-        }
-        ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y);
-        if (!mAnimationFilter.animateY) {
-            // just a local update was performed
-            if (previousAnimator != null) {
-                // we need to increase all animation keyframes of the previous animator by the
-                // relative change to the end value
-                PropertyValuesHolder[] values = previousAnimator.getValues();
-                float relativeDiff = newEndValue - previousEndValue;
-                float newStartValue = previousStartValue + relativeDiff;
-                values[0].setFloatValues(newStartValue, newEndValue);
-                child.setTag(TAG_START_TRANSLATION_Y, newStartValue);
-                child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
-                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
-                return;
-            } else {
-                // no new animation needed, let's just apply the value
-                child.setTranslationY(newEndValue);
-                return;
-            }
-        }
-
-        ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Y,
-                child.getTranslationY(), newEndValue);
-        Interpolator interpolator = mHeadsUpAppearChildren.contains(child) ?
-                mHeadsUpAppearInterpolator :Interpolators.FAST_OUT_SLOW_IN;
-        animator.setInterpolator(interpolator);
-        long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
-        animator.setDuration(newDuration);
-        if (delay > 0 && (previousAnimator == null
-                || previousAnimator.getAnimatedFraction() == 0)) {
-            animator.setStartDelay(delay);
-        }
-        animator.addListener(getGlobalAnimationFinishedListener());
-        final boolean isHeadsUpDisappear = mHeadsUpDisappearChildren.contains(child);
-        // remove the tag when the animation is finished
-        animator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                HeadsUpManager.setIsClickedNotification(child, false);
-                child.setTag(TAG_ANIMATOR_TRANSLATION_Y, null);
-                child.setTag(TAG_START_TRANSLATION_Y, null);
-                child.setTag(TAG_END_TRANSLATION_Y, null);
-                if (isHeadsUpDisappear) {
-                    ((ExpandableNotificationRow) child).setHeadsupDisappearRunning(false);
-                }
-            }
-        });
-        startAnimator(animator);
-        child.setTag(TAG_ANIMATOR_TRANSLATION_Y, animator);
-        child.setTag(TAG_START_TRANSLATION_Y, child.getTranslationY());
-        child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
-    }
-
-    private void startAnimator(ValueAnimator animator) {
-        mAnimatorSet.add(animator);
-        animator.start();
+        result += (long) (index * ANIMATION_DELAY_PER_ELEMENT_GO_TO_FULL_SHADE);
+        return result;
     }
 
     /**
@@ -814,33 +333,11 @@
             @Override
             public void onAnimationStart(Animator animation) {
                 mWasCancelled = false;
+                mAnimatorSet.add(animation);
             }
         };
     }
 
-    public static <T> T getChildTag(View child, int tag) {
-        return (T) child.getTag(tag);
-    }
-
-    /**
-     * Cancel the previous animator and get the duration of the new animation.
-     *
-     * @param duration the new duration
-     * @param previousAnimator the animator which was running before
-     * @return the new duration
-     */
-    private long cancelAnimatorAndGetNewDuration(long duration, ValueAnimator previousAnimator) {
-        long newDuration = duration;
-        if (previousAnimator != null) {
-            // We take either the desired length of the new animation or the remaining time of
-            // the previous animator, whichever is longer.
-            newDuration = Math.max(previousAnimator.getDuration()
-                    - previousAnimator.getCurrentPlayTime(), newDuration);
-            previousAnimator.cancel();
-        }
-        return newDuration;
-    }
-
     private void onAnimationFinished() {
         mHostLayout.onChildAnimationFinished();
         for (View v : mChildrenToClearFromOverlay) {
@@ -864,25 +361,25 @@
                     NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD) {
 
                 // This item is added, initialize it's properties.
-                StackViewState viewState = finalState
+                ExpandableViewState viewState = finalState
                         .getViewStateForView(changingView);
                 if (viewState == null) {
                     // The position for this child was never generated, let's continue.
                     continue;
                 }
-                finalState.applyState(changingView, viewState);
+                viewState.applyToView(changingView);
                 mNewAddChildren.add(changingView);
 
             } else if (event.animationType ==
                     NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE) {
-                if (changingView.getVisibility() == View.GONE) {
+                if (changingView.getVisibility() != View.VISIBLE) {
                     removeFromOverlay(changingView);
                     continue;
                 }
 
                 // Find the amount to translate up. This is needed in order to understand the
                 // direction of the remove animation (either downwards or upwards)
-                StackViewState viewState = finalState
+                ExpandableViewState viewState = finalState
                         .getViewStateForView(event.viewAfterChangingView);
                 int actualHeight = changingView.getActualHeight();
                 // upwards by default
@@ -920,7 +417,7 @@
             } else if (event.animationType == NotificationStackScrollLayout
                     .AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR) {
                 // This item is added, initialize it's properties.
-                StackViewState viewState = finalState.getViewStateForView(changingView);
+                ExpandableViewState viewState = finalState.getViewStateForView(changingView);
                 mTmpState.copyFrom(viewState);
                 if (event.headsUpFromBottom) {
                     mTmpState.yTranslation = mHeadsUpAppearHeightBottom;
@@ -928,7 +425,7 @@
                     mTmpState.yTranslation = -mTmpState.height;
                 }
                 mHeadsUpAppearChildren.add(changingView);
-                finalState.applyState(changingView, mTmpState);
+                mTmpState.applyToView(changingView);
             } else if (event.animationType == NotificationStackScrollLayout
                             .AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR ||
                     event.animationType == NotificationStackScrollLayout
@@ -942,12 +439,13 @@
                     // We temporarily enable Y animations, the real filter will be combined
                     // afterwards anyway
                     mAnimationFilter.animateY = true;
-                    startViewAnimations(changingView, mTmpState,
+                    mAnimationProperties.delay =
                             event.animationType == NotificationStackScrollLayout
                                     .AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK
-                                            ? ANIMATION_DELAY_HEADS_UP
-                                            : 0,
-                            ANIMATION_DURATION_HEADS_UP_DISAPPEAR);
+                            ? ANIMATION_DELAY_HEADS_UP
+                            : 0;
+                    mAnimationProperties.duration = ANIMATION_DURATION_HEADS_UP_DISAPPEAR;
+                    mTmpState.animateTo(changingView, mAnimationProperties);
                     mChildrenToClearFromOverlay.add(changingView);
                 }
             }
@@ -1007,38 +505,6 @@
         }
     }
 
-    /**
-     * Get the end value of the height animation running on a view or the actualHeight
-     * if no animation is running.
-     */
-    public static int getFinalActualHeight(ExpandableView view) {
-        if (view == null) {
-            return 0;
-        }
-        ValueAnimator heightAnimator = getChildTag(view, TAG_ANIMATOR_HEIGHT);
-        if (heightAnimator == null) {
-            return view.getActualHeight();
-        } else {
-            return getChildTag(view, TAG_END_HEIGHT);
-        }
-    }
-
-    /**
-     * Get the end value of the yTranslation animation running on a view or the yTranslation
-     * if no animation is running.
-     */
-    public static float getFinalTranslationY(View view) {
-        if (view == null) {
-            return 0;
-        }
-        ValueAnimator yAnimator = getChildTag(view, TAG_ANIMATOR_TRANSLATION_Y);
-        if (yAnimator == null) {
-            return view.getTranslationY();
-        } else {
-            return getChildTag(view, TAG_END_TRANSLATION_Y);
-        }
-    }
-
     public void setHeadsUpAppearHeightBottom(int headsUpAppearHeightBottom) {
         mHeadsUpAppearHeightBottom = headsUpAppearHeightBottom;
     }
@@ -1046,4 +512,8 @@
     public void setShadeExpanded(boolean shadeExpanded) {
         mShadeExpanded = shadeExpanded;
     }
+
+    public void setShelf(NotificationShelf shelf) {
+        mShelf = shelf;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java
deleted file mode 100644
index ecdee4e..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.stack;
-
-/**
-* A state of an expandable view
-*/
-public class StackViewState extends ViewState {
-
-    // These are flags such that we can create masks for filtering.
-
-    public static final int LOCATION_UNKNOWN = 0x00;
-    public static final int LOCATION_FIRST_HUN = 0x01;
-    public static final int LOCATION_HIDDEN_TOP = 0x02;
-    public static final int LOCATION_MAIN_AREA = 0x04;
-    public static final int LOCATION_BOTTOM_STACK_PEEKING = 0x08;
-    public static final int LOCATION_BOTTOM_STACK_HIDDEN = 0x10;
-    /** The view isn't layouted at all. */
-    public static final int LOCATION_GONE = 0x40;
-
-    public int height;
-    public boolean dimmed;
-    public boolean dark;
-    public boolean hideSensitive;
-    public boolean belowSpeedBump;
-    public float shadowAlpha;
-
-    /**
-     * How much the child overlaps with the previous child on top. This is used to
-     * show the background properly when the child on top is translating away.
-     */
-    public int clipTopAmount;
-
-    /**
-     * The index of the view, only accounting for views not equal to GONE
-     */
-    public int notGoneIndex;
-
-    /**
-     * The location this view is currently rendered at.
-     *
-     * <p>See <code>LOCATION_</code> flags.</p>
-     */
-    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);
-        if (viewState instanceof StackViewState) {
-            StackViewState svs = (StackViewState) viewState;
-            height = svs.height;
-            dimmed = svs.dimmed;
-            shadowAlpha = svs.shadowAlpha;
-            dark = svs.dark;
-            hideSensitive = svs.hideSensitive;
-            belowSpeedBump = svs.belowSpeedBump;
-            clipTopAmount = svs.clipTopAmount;
-            notGoneIndex = svs.notGoneIndex;
-            location = svs.location;
-            isBottomClipped = svs.isBottomClipped;
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
index 5beaac3..8a5ddd4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
@@ -16,7 +16,18 @@
 
 package com.android.systemui.statusbar.stack;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
 import android.view.View;
+import android.view.animation.Interpolator;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.ExpandableView;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 /**
  * A state of a view. This can be used to apply a set of view properties to a view with
@@ -25,25 +36,519 @@
 */
 public class ViewState {
 
+    /**
+     * Some animation properties that can be used to update running animations but not creating
+     * any new ones.
+     */
+    protected static final AnimationProperties NO_NEW_ANIMATIONS = new AnimationProperties() {
+        AnimationFilter mAnimationFilter = new AnimationFilter();
+        @Override
+        public AnimationFilter getAnimationFilter() {
+            return mAnimationFilter;
+        }
+    };
+    private static final int TAG_ANIMATOR_TRANSLATION_X = R.id.translation_x_animator_tag;
+    private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag;
+    private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag;
+    private static final int TAG_ANIMATOR_ALPHA = R.id.alpha_animator_tag;
+    private static final int TAG_END_TRANSLATION_X = R.id.translation_x_animator_end_value_tag;
+    private static final int TAG_END_TRANSLATION_Y = R.id.translation_y_animator_end_value_tag;
+    private static final int TAG_END_TRANSLATION_Z = R.id.translation_z_animator_end_value_tag;
+    private static final int TAG_END_ALPHA = R.id.alpha_animator_end_value_tag;
+    private static final int TAG_START_TRANSLATION_X = R.id.translation_x_animator_start_value_tag;
+    private static final int TAG_START_TRANSLATION_Y = R.id.translation_y_animator_start_value_tag;
+    private static final int TAG_START_TRANSLATION_Z = R.id.translation_z_animator_start_value_tag;
+    private static final int TAG_START_ALPHA = R.id.alpha_animator_start_value_tag;
+
     public float alpha;
+    public float xTranslation;
     public float yTranslation;
     public float zTranslation;
     public boolean gone;
     public boolean hidden;
+    public float scaleX = 1.0f;
+    public float scaleY = 1.0f;
 
     public void copyFrom(ViewState viewState) {
         alpha = viewState.alpha;
+        xTranslation = viewState.xTranslation;
         yTranslation = viewState.yTranslation;
         zTranslation = viewState.zTranslation;
         gone = viewState.gone;
         hidden = viewState.hidden;
+        scaleX = viewState.scaleX;
+        scaleY = viewState.scaleY;
     }
 
     public void initFrom(View view) {
         alpha = view.getAlpha();
+        xTranslation = view.getTranslationX();
         yTranslation = view.getTranslationY();
         zTranslation = view.getTranslationZ();
         gone = view.getVisibility() == View.GONE;
         hidden = false;
+        scaleX = view.getScaleX();
+        scaleY = view.getScaleY();
+    }
+
+    /**
+     * Applies a {@link ViewState} to a normal view.
+     */
+    public void applyToView(View view) {
+        if (this.gone) {
+            // don't do anything with it
+            return;
+        }
+        boolean becomesInvisible = this.alpha == 0.0f || this.hidden;
+        boolean animatingAlpha = isAnimating(view, TAG_ANIMATOR_ALPHA);
+        if (animatingAlpha) {
+            updateAlphaAnimation(view);
+        } else if (view.getAlpha() != this.alpha) {
+            // apply layer type
+            boolean becomesFullyVisible = this.alpha == 1.0f;
+            boolean newLayerTypeIsHardware = !becomesInvisible && !becomesFullyVisible
+                    && view.hasOverlappingRendering();
+            int layerType = view.getLayerType();
+            int newLayerType = newLayerTypeIsHardware
+                    ? View.LAYER_TYPE_HARDWARE
+                    : View.LAYER_TYPE_NONE;
+            if (layerType != newLayerType) {
+                view.setLayerType(newLayerType, null);
+            }
+
+            // apply alpha
+            view.setAlpha(this.alpha);
+        }
+
+        // apply visibility
+        int oldVisibility = view.getVisibility();
+        int newVisibility = becomesInvisible ? View.INVISIBLE : View.VISIBLE;
+        if (newVisibility != oldVisibility) {
+            if (!(view instanceof ExpandableView) || !((ExpandableView) view).willBeGone()) {
+                // We don't want views to change visibility when they are animating to GONE
+                view.setVisibility(newVisibility);
+            }
+        }
+
+        // apply xTranslation
+        boolean animatingX = isAnimating(view, TAG_ANIMATOR_TRANSLATION_X);
+        if (animatingX) {
+            updateAnimationX(view);
+        } else if (view.getTranslationX() != this.xTranslation){
+            view.setTranslationX(this.xTranslation);
+        }
+
+        // apply yTranslation
+        boolean animatingY = isAnimating(view, TAG_ANIMATOR_TRANSLATION_Y);
+        if (animatingY) {
+            updateAnimationY(view);
+        } else if (view.getTranslationY() != this.yTranslation) {
+            view.setTranslationY(this.yTranslation);
+        }
+
+        // apply zTranslation
+        boolean animatingZ = isAnimating(view, TAG_ANIMATOR_TRANSLATION_Z);
+        if (animatingZ) {
+            updateAnimationZ(view);
+        } else if (view.getTranslationZ() != this.zTranslation) {
+            view.setTranslationZ(this.zTranslation);
+        }
+
+        // apply scaleX
+        if (view.getScaleX() != this.scaleX) {
+            view.setScaleX(this.scaleX);
+        }
+
+        // apply scaleY
+        if (view.getScaleY() != this.scaleY) {
+            view.setScaleY(this.scaleY);
+        }
+    }
+
+    private boolean isAnimating(View view, int tag) {
+        return getChildTag(view, tag) != null;
+    }
+
+    /**
+     * Start an animation to this viewstate
+     * @param child the view to animate
+     * @param animationProperties the properties of the animation
+     */
+    public void animateTo(View child, AnimationProperties animationProperties) {
+        boolean wasVisible = child.getVisibility() == View.VISIBLE;
+        final float alpha = this.alpha;
+        if (!wasVisible && (alpha != 0 || child.getAlpha() != 0)
+                && !this.gone && !this.hidden) {
+            child.setVisibility(View.VISIBLE);
+        }
+        float childAlpha = child.getAlpha();
+        boolean alphaChanging = this.alpha != childAlpha;
+        if (child instanceof ExpandableView) {
+            // We don't want views to change visibility when they are animating to GONE
+            alphaChanging &= !((ExpandableView) child).willBeGone();
+        }
+
+        // start translationX animation
+        if (child.getTranslationX() != this.xTranslation) {
+            startXTranslationAnimation(child, animationProperties);
+        } else {
+            abortAnimation(child, TAG_ANIMATOR_TRANSLATION_X);
+        }
+
+        // start translationY animation
+        if (child.getTranslationY() != this.yTranslation) {
+            startYTranslationAnimation(child, animationProperties);
+        } else {
+            abortAnimation(child, TAG_ANIMATOR_TRANSLATION_Y);
+        }
+
+        // start translationZ animation
+        if (child.getTranslationZ() != this.zTranslation) {
+            startZTranslationAnimation(child, animationProperties);
+        } else {
+            abortAnimation(child, TAG_ANIMATOR_TRANSLATION_Z);
+        }
+
+        // start alpha animation
+        if (alphaChanging) {
+            startAlphaAnimation(child, animationProperties);
+        }  else {
+            abortAnimation(child, TAG_ANIMATOR_ALPHA);
+        }
+    }
+
+    private void updateAlphaAnimation(View view) {
+        startAlphaAnimation(view, NO_NEW_ANIMATIONS);
+    }
+
+    private void startAlphaAnimation(final View child, AnimationProperties properties) {
+        Float previousStartValue = getChildTag(child,TAG_START_ALPHA);
+        Float previousEndValue = getChildTag(child,TAG_END_ALPHA);
+        final float newEndValue = this.alpha;
+        if (previousEndValue != null && previousEndValue == newEndValue) {
+            return;
+        }
+        ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_ALPHA);
+        AnimationFilter filter = properties.getAnimationFilter();
+        if (!filter.animateAlpha) {
+            // just a local update was performed
+            if (previousAnimator != null) {
+                // we need to increase all animation keyframes of the previous animator by the
+                // relative change to the end value
+                PropertyValuesHolder[] values = previousAnimator.getValues();
+                float relativeDiff = newEndValue - previousEndValue;
+                float newStartValue = previousStartValue + relativeDiff;
+                values[0].setFloatValues(newStartValue, newEndValue);
+                child.setTag(TAG_START_ALPHA, newStartValue);
+                child.setTag(TAG_END_ALPHA, newEndValue);
+                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+                return;
+            } else {
+                // no new animation needed, let's just apply the value
+                child.setAlpha(newEndValue);
+                if (newEndValue == 0) {
+                    child.setVisibility(View.INVISIBLE);
+                }
+            }
+        }
+
+        ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.ALPHA,
+                child.getAlpha(), newEndValue);
+        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+        // Handle layer type
+        child.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+        animator.addListener(new AnimatorListenerAdapter() {
+            public boolean mWasCancelled;
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                child.setLayerType(View.LAYER_TYPE_NONE, null);
+                if (newEndValue == 0 && !mWasCancelled) {
+                    child.setVisibility(View.INVISIBLE);
+                }
+                // remove the tag when the animation is finished
+                child.setTag(TAG_ANIMATOR_ALPHA, null);
+                child.setTag(TAG_START_ALPHA, null);
+                child.setTag(TAG_END_ALPHA, null);
+            }
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                mWasCancelled = true;
+            }
+
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mWasCancelled = false;
+            }
+        });
+        long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator);
+        animator.setDuration(newDuration);
+        if (properties.delay > 0 && (previousAnimator == null
+                || previousAnimator.getAnimatedFraction() == 0)) {
+            animator.setStartDelay(properties.delay);
+        }
+        AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+        if (listener != null) {
+            animator.addListener(listener);
+        }
+
+        startAnimator(animator, listener);
+        child.setTag(TAG_ANIMATOR_ALPHA, animator);
+        child.setTag(TAG_START_ALPHA, child.getAlpha());
+        child.setTag(TAG_END_ALPHA, newEndValue);
+    }
+
+    private void updateAnimationZ(View view) {
+        startZTranslationAnimation(view, NO_NEW_ANIMATIONS);
+    }
+
+    private void startZTranslationAnimation(final View child, AnimationProperties properties) {
+        Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Z);
+        Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Z);
+        float newEndValue = this.zTranslation;
+        if (previousEndValue != null && previousEndValue == newEndValue) {
+            return;
+        }
+        ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Z);
+        AnimationFilter filter = properties.getAnimationFilter();
+        if (!filter.animateZ) {
+            // just a local update was performed
+            if (previousAnimator != null) {
+                // we need to increase all animation keyframes of the previous animator by the
+                // relative change to the end value
+                PropertyValuesHolder[] values = previousAnimator.getValues();
+                float relativeDiff = newEndValue - previousEndValue;
+                float newStartValue = previousStartValue + relativeDiff;
+                values[0].setFloatValues(newStartValue, newEndValue);
+                child.setTag(TAG_START_TRANSLATION_Z, newStartValue);
+                child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
+                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+                return;
+            } else {
+                // no new animation needed, let's just apply the value
+                child.setTranslationZ(newEndValue);
+            }
+        }
+
+        ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Z,
+                child.getTranslationZ(), newEndValue);
+        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+        long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator);
+        animator.setDuration(newDuration);
+        if (properties.delay > 0 && (previousAnimator == null
+                || previousAnimator.getAnimatedFraction() == 0)) {
+            animator.setStartDelay(properties.delay);
+        }
+        AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+        if (listener != null) {
+            animator.addListener(listener);
+        }
+        // remove the tag when the animation is finished
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                child.setTag(TAG_ANIMATOR_TRANSLATION_Z, null);
+                child.setTag(TAG_START_TRANSLATION_Z, null);
+                child.setTag(TAG_END_TRANSLATION_Z, null);
+            }
+        });
+        startAnimator(animator, listener);
+        child.setTag(TAG_ANIMATOR_TRANSLATION_Z, animator);
+        child.setTag(TAG_START_TRANSLATION_Z, child.getTranslationZ());
+        child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
+    }
+
+    private void updateAnimationX(View view) {
+        startXTranslationAnimation(view, NO_NEW_ANIMATIONS);
+    }
+
+    private void startXTranslationAnimation(final View child, AnimationProperties properties) {
+        Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_X);
+        Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_X);
+        float newEndValue = this.xTranslation;
+        if (previousEndValue != null && previousEndValue == newEndValue) {
+            return;
+        }
+        ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_X);
+        AnimationFilter filter = properties.getAnimationFilter();
+        if (!filter.animateX) {
+            // just a local update was performed
+            if (previousAnimator != null) {
+                // we need to increase all animation keyframes of the previous animator by the
+                // relative change to the end value
+                PropertyValuesHolder[] values = previousAnimator.getValues();
+                float relativeDiff = newEndValue - previousEndValue;
+                float newStartValue = previousStartValue + relativeDiff;
+                values[0].setFloatValues(newStartValue, newEndValue);
+                child.setTag(TAG_START_TRANSLATION_X, newStartValue);
+                child.setTag(TAG_END_TRANSLATION_X, newEndValue);
+                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+                return;
+            } else {
+                // no new animation needed, let's just apply the value
+                child.setTranslationX(newEndValue);
+                return;
+            }
+        }
+
+        ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_X,
+                child.getTranslationX(), newEndValue);
+        Interpolator customInterpolator = properties.getCustomInterpolator(child,
+                View.TRANSLATION_X);
+        Interpolator interpolator =  customInterpolator != null ? customInterpolator
+                : Interpolators.FAST_OUT_SLOW_IN;
+        animator.setInterpolator(interpolator);
+        long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator);
+        animator.setDuration(newDuration);
+        if (properties.delay > 0 && (previousAnimator == null
+                || previousAnimator.getAnimatedFraction() == 0)) {
+            animator.setStartDelay(properties.delay);
+        }
+        AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+        if (listener != null) {
+            animator.addListener(listener);
+        }
+        // remove the tag when the animation is finished
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                child.setTag(TAG_ANIMATOR_TRANSLATION_X, null);
+                child.setTag(TAG_START_TRANSLATION_X, null);
+                child.setTag(TAG_END_TRANSLATION_X, null);
+            }
+        });
+        startAnimator(animator, listener);
+        child.setTag(TAG_ANIMATOR_TRANSLATION_X, animator);
+        child.setTag(TAG_START_TRANSLATION_X, child.getTranslationX());
+        child.setTag(TAG_END_TRANSLATION_X, newEndValue);
+    }
+
+    private void updateAnimationY(View view) {
+        startYTranslationAnimation(view, NO_NEW_ANIMATIONS);
+    }
+
+    private void startYTranslationAnimation(final View child, AnimationProperties properties) {
+        Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Y);
+        Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Y);
+        float newEndValue = this.yTranslation;
+        if (previousEndValue != null && previousEndValue == newEndValue) {
+            return;
+        }
+        ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y);
+        AnimationFilter filter = properties.getAnimationFilter();
+        if (!filter.animateY) {
+            // just a local update was performed
+            if (previousAnimator != null) {
+                // we need to increase all animation keyframes of the previous animator by the
+                // relative change to the end value
+                PropertyValuesHolder[] values = previousAnimator.getValues();
+                float relativeDiff = newEndValue - previousEndValue;
+                float newStartValue = previousStartValue + relativeDiff;
+                values[0].setFloatValues(newStartValue, newEndValue);
+                child.setTag(TAG_START_TRANSLATION_Y, newStartValue);
+                child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
+                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+                return;
+            } else {
+                // no new animation needed, let's just apply the value
+                child.setTranslationY(newEndValue);
+                return;
+            }
+        }
+
+        ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Y,
+                child.getTranslationY(), newEndValue);
+        Interpolator customInterpolator = properties.getCustomInterpolator(child,
+                View.TRANSLATION_Y);
+        Interpolator interpolator =  customInterpolator != null ? customInterpolator
+                : Interpolators.FAST_OUT_SLOW_IN;
+        animator.setInterpolator(interpolator);
+        long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator);
+        animator.setDuration(newDuration);
+        if (properties.delay > 0 && (previousAnimator == null
+                || previousAnimator.getAnimatedFraction() == 0)) {
+            animator.setStartDelay(properties.delay);
+        }
+        AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+        if (listener != null) {
+            animator.addListener(listener);
+        }
+        // remove the tag when the animation is finished
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                HeadsUpManager.setIsClickedNotification(child, false);
+                child.setTag(TAG_ANIMATOR_TRANSLATION_Y, null);
+                child.setTag(TAG_START_TRANSLATION_Y, null);
+                child.setTag(TAG_END_TRANSLATION_Y, null);
+                onYTranslationAnimationFinished();
+            }
+        });
+        startAnimator(animator, listener);
+        child.setTag(TAG_ANIMATOR_TRANSLATION_Y, animator);
+        child.setTag(TAG_START_TRANSLATION_Y, child.getTranslationY());
+        child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
+    }
+
+    protected void onYTranslationAnimationFinished() {
+    }
+
+    protected void startAnimator(Animator animator, AnimatorListenerAdapter listener) {
+        if (listener != null) {
+            // Even if there's a delay we'd want to notify it of the start immediately.
+            listener.onAnimationStart(animator);
+        }
+        animator.start();
+    }
+
+    public static <T> T getChildTag(View child, int tag) {
+        return (T) child.getTag(tag);
+    }
+
+    protected void abortAnimation(View child, int animatorTag) {
+        Animator previousAnimator = getChildTag(child, animatorTag);
+        if (previousAnimator != null) {
+            previousAnimator.cancel();
+        }
+    }
+
+    /**
+     * Cancel the previous animator and get the duration of the new animation.
+     *
+     * @param duration the new duration
+     * @param previousAnimator the animator which was running before
+     * @return the new duration
+     */
+    protected long cancelAnimatorAndGetNewDuration(long duration, ValueAnimator previousAnimator) {
+        long newDuration = duration;
+        if (previousAnimator != null) {
+            // We take either the desired length of the new animation or the remaining time of
+            // the previous animator, whichever is longer.
+            newDuration = Math.max(previousAnimator.getDuration()
+                    - previousAnimator.getCurrentPlayTime(), newDuration);
+            previousAnimator.cancel();
+        }
+        return newDuration;
+    }
+
+    /**
+     * Get the end value of the yTranslation animation running on a view or the yTranslation
+     * if no animation is running.
+     */
+    public static float getFinalTranslationY(View view) {
+        if (view == null) {
+            return 0;
+        }
+        ValueAnimator yAnimator = getChildTag(view, TAG_ANIMATOR_TRANSLATION_Y);
+        if (yAnimator == null) {
+            return view.getTranslationY();
+        } else {
+            return getChildTag(view, TAG_END_TRANSLATION_Y);
+        }
+    }
+
+    public static boolean isAnimatingY(ExpandableView child) {
+        return getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y) != null;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
index c20cc84..bb5632b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
@@ -78,6 +78,7 @@
         AudioSystem.STREAM_SYSTEM_ENFORCED,
         AudioSystem.STREAM_TTS,
         AudioSystem.STREAM_VOICE_CALL,
+        AudioSystem.STREAM_ACCESSIBILITY,
     };
 
     private final HandlerThread mWorkerThread;
@@ -119,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();
     }
@@ -562,6 +582,22 @@
                     .sendToTarget();
             mWorker.sendEmptyMessage(W.DISMISS_REQUESTED);
         }
+
+        @Override
+        public void setA11yMode(int mode) {
+            if (D.BUG) Log.d(TAG, "setA11yMode to " + mode);
+            if (mDestroyed) return;
+            switch (mode) {
+                case VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME:
+                    // "legacy" mode
+                    break;
+                case VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME:
+                    break;
+                default:
+                    Log.e(TAG, "Invalid accessibility mode " + mode);
+                    break;
+            }
+        }
     }
 
     private final class W extends Handler {
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/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
index 863f0e5..8b99d72 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -202,6 +202,18 @@
 
     @Test
     @UiThreadTest
+    public void testPulseDuringPulse_doesntCrash() {
+        mMachine.requestState(INITIALIZED);
+
+        mMachine.requestState(DOZE);
+        mMachine.requestState(DOZE_REQUEST_PULSE);
+        mMachine.requestState(DOZE_PULSING);
+        mMachine.requestState(DOZE_REQUEST_PULSE);
+        mMachine.requestState(DOZE_PULSE_DONE);
+    }
+
+    @Test
+    @UiThreadTest
     public void testScreen_offInDoze() {
         mMachine.requestState(INITIALIZED);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java
new file mode 100644
index 0000000..131a70b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.keyguard;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.policy.IKeyguardDismissCallback;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * runtest systemui -c com.android.systemui.keyguard.DismissCallbackRegistryTest
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DismissCallbackRegistryTest {
+
+    private final DismissCallbackRegistry mDismissCallbackRegistry = new DismissCallbackRegistry();
+    private @Mock IKeyguardDismissCallback mMockCallback;
+    private @Mock IKeyguardDismissCallback mMockCallback2;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testCancelled() throws Exception {
+        mDismissCallbackRegistry.addCallback(mMockCallback);
+        mDismissCallbackRegistry.notifyDismissCancelled();
+        verify(mMockCallback).onDismissCancelled();
+    }
+
+    @Test
+    public void testCancelled_multiple() throws Exception {
+        mDismissCallbackRegistry.addCallback(mMockCallback);
+        mDismissCallbackRegistry.addCallback(mMockCallback2);
+        mDismissCallbackRegistry.notifyDismissCancelled();
+        verify(mMockCallback).onDismissCancelled();
+        verify(mMockCallback2).onDismissCancelled();
+    }
+
+    @Test
+    public void testSucceeded() throws Exception {
+        mDismissCallbackRegistry.addCallback(mMockCallback);
+        mDismissCallbackRegistry.notifyDismissSucceeded();
+        verify(mMockCallback).onDismissSucceeded();
+    }
+
+    @Test
+    public void testSucceeded_multiple() throws Exception {
+        mDismissCallbackRegistry.addCallback(mMockCallback);
+        mDismissCallbackRegistry.addCallback(mMockCallback2);
+        mDismissCallbackRegistry.notifyDismissSucceeded();
+        verify(mMockCallback).onDismissSucceeded();
+        verify(mMockCallback2).onDismissSucceeded();
+    }
+
+    @Test
+    public void testOnlyOnce() throws Exception {
+        mDismissCallbackRegistry.addCallback(mMockCallback);
+        mDismissCallbackRegistry.notifyDismissSucceeded();
+        mDismissCallbackRegistry.notifyDismissSucceeded();
+        verify(mMockCallback, times(1)).onDismissSucceeded();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterTest.java
new file mode 100644
index 0000000..1987009
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterTest.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Looper;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.SpannableStringBuilder;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.policy.SecurityController;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static junit.framework.Assert.assertEquals;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.eq;
+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 QSFooterTest extends SysuiTestCase {
+
+    private final String MANAGING_ORGANIZATION = "organization";
+    private final String DEVICE_OWNER_PACKAGE = "TestDPC";
+    private final String VPN_PACKAGE = "TestVPN";
+
+    private ViewGroup mRootView = mock(ViewGroup.class);
+    private TextView mFooterText = mock(TextView.class);
+    private QSFooter mFooter;
+    private Resources mResources;
+    private SecurityController mSecurityController = mock(SecurityController.class);
+
+    @Before
+    public void setUp() {
+        when(mRootView.findViewById(R.id.footer_text)).thenReturn(mFooterText);
+        when(mRootView.findViewById(R.id.footer_icon)).thenReturn(mock(ImageView.class));
+        final LayoutInflater layoutInflater = mock(LayoutInflater.class);
+        when(layoutInflater.inflate(eq(R.layout.quick_settings_footer), anyObject(), anyBoolean()))
+                .thenReturn(mRootView);
+        final Context context = mock(Context.class);
+        when(context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).thenReturn(layoutInflater);
+        mResources = mContext.getResources();
+        when(context.getResources()).thenReturn(mResources);
+        mFooter = new QSFooter(null, context);
+        reset(mRootView);
+        mFooter.setHostEnvironment(null, mSecurityController, Looper.getMainLooper());
+    }
+
+    @Test
+    public void testUnmanaged() {
+        when(mSecurityController.isDeviceManaged()).thenReturn(false);
+        when(mSecurityController.isVpnEnabled()).thenReturn(false);
+        when(mSecurityController.isVpnBranded()).thenReturn(false);
+        mFooter.refreshState();
+
+        waitForIdleSync(mFooter.mHandler);
+        verify(mRootView).setVisibility(View.GONE);
+        verifyNoMoreInteractions(mRootView);
+    }
+
+    @Test
+    public void testManagedNoOwnerName() {
+        when(mSecurityController.isDeviceManaged()).thenReturn(true);
+        when(mSecurityController.getDeviceOwnerOrganizationName()).thenReturn(null);
+        mFooter.refreshState();
+
+        waitForIdleSync(mFooter.mHandler);
+        verify(mFooterText).setText(mResources.getString(R.string.do_disclosure_generic));
+        verifyNoMoreInteractions(mFooterText);
+        verify(mRootView).setVisibility(View.VISIBLE);
+        verifyNoMoreInteractions(mRootView);
+    }
+
+    @Test
+    public void testManagedOwnerName() {
+        when(mSecurityController.isDeviceManaged()).thenReturn(true);
+        when(mSecurityController.getDeviceOwnerOrganizationName())
+                .thenReturn(MANAGING_ORGANIZATION);
+        mFooter.refreshState();
+
+        waitForIdleSync(mFooter.mHandler);
+        verify(mFooterText).setText(mResources.getString(R.string.do_disclosure_with_name,
+                MANAGING_ORGANIZATION));
+        verifyNoMoreInteractions(mFooterText);
+        verify(mRootView).setVisibility(View.VISIBLE);
+        verifyNoMoreInteractions(mRootView);
+    }
+
+    @Test
+    public void testGetMessageWithNoOrganizationAndNoVPN() {
+        assertEquals(getExpectedMessage(false /* hasDeviceOwnerOrganization */, false /* hasVPN */),
+                mFooter.getMessage(DEVICE_OWNER_PACKAGE,
+                        null /* profileOwnerPackage */,
+                        null /* primaryVpn */,
+                        null /* profileVpn */,
+                        null /* deviceOwnerOrganization */,
+                        false /* hasProfileOwner */,
+                        false /* isBranded */));
+    }
+
+    @Test
+    public void testGetMessageWithNoOrganizationAndVPN() {
+        assertEquals(getExpectedMessage(false /* hasDeviceOwnerOrganization */, true /* hasVPN */),
+                mFooter.getMessage(DEVICE_OWNER_PACKAGE,
+                        null /* profileOwnerPackage */,
+                        VPN_PACKAGE,
+                        null /* profileVpn */,
+                        null /* deviceOwnerOrganization */,
+                        false /* hasProfileOwner */,
+                        false /* isBranded */));
+    }
+
+    @Test
+    public void testGetMessageWithOrganizationAndNoVPN() {
+        assertEquals(getExpectedMessage(true /* hasDeviceOwnerOrganization */, false /* hasVPN */),
+                mFooter.getMessage(DEVICE_OWNER_PACKAGE,
+                        null /* profileOwnerPackage */,
+                        null /* primaryVpn */,
+                        null /* profileVpn */,
+                        MANAGING_ORGANIZATION,
+                        false /* hasProfileOwner */,
+                        false /* isBranded */));
+    }
+
+    @Test
+    public void testGetMessageWithOrganizationAndVPN() {
+        assertEquals(getExpectedMessage(true /* hasDeviceOwnerOrganization */, true /* hasVPN */),
+                mFooter.getMessage(DEVICE_OWNER_PACKAGE,
+                        null /* profileOwnerPackage */,
+                        VPN_PACKAGE,
+                        null /* profileVpn */,
+                        MANAGING_ORGANIZATION,
+                        false /* hasProfileOwner */,
+                        false /* isBranded */));
+    }
+
+    private CharSequence getExpectedMessage(boolean hasDeviceOwnerOrganization, boolean hasVPN) {
+        final SpannableStringBuilder message = new SpannableStringBuilder();
+        message.append(hasDeviceOwnerOrganization ?
+                mResources.getString(R.string.monitoring_description_do_header_with_name,
+                        MANAGING_ORGANIZATION, DEVICE_OWNER_PACKAGE) :
+                mResources.getString(R.string.monitoring_description_do_header_generic,
+                        DEVICE_OWNER_PACKAGE));
+        message.append("\n\n");
+        message.append(mResources.getString(R.string.monitoring_description_do_body));
+        if (hasVPN) {
+            message.append("\n\n");
+            message.append(mResources.getString(R.string.monitoring_description_do_body_vpn,
+                    VPN_PACKAGE));
+        }
+        message.append(mResources.getString(
+                R.string.monitoring_description_do_learn_more_separator));
+        message.append(mResources.getString(R.string.monitoring_description_do_learn_more),
+                mFooter.new EnterprisePrivacySpan(), 0);
+        return message;
+    }
+}
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/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
new file mode 100644
index 0000000..9a697ee
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.net.ConnectivityManager;
+import android.os.UserManager;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SecurityControllerTest extends SysuiTestCase {
+    private final DevicePolicyManager mDevicePolicyManager = mock(DevicePolicyManager.class);
+    private SecurityControllerImpl mSecurityController;
+
+    @Before
+    public void setUp() throws Exception {
+        final Context context = mock(Context.class);
+        when(context.getSystemService(Context.DEVICE_POLICY_SERVICE))
+                .thenReturn(mDevicePolicyManager);
+        when(context.getSystemService(Context.CONNECTIVITY_SERVICE))
+                .thenReturn(mock(ConnectivityManager.class));
+        final UserManager userManager = mock(UserManager.class);
+        when(userManager.getUserInfo(anyInt())).thenReturn(mock(UserInfo.class));
+        when(context.getSystemService(Context.USER_SERVICE))
+                .thenReturn(userManager);
+        mSecurityController = new SecurityControllerImpl(context);
+    }
+
+    @Test
+    public void testIsDeviceManaged() {
+        when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
+        assertTrue(mSecurityController.isDeviceManaged());
+
+        when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
+        assertFalse(mSecurityController.isDeviceManaged());
+    }
+
+    @Test
+    public void testGetDeviceOwnerOrganizationName() {
+        when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn("organization");
+        assertEquals("organization", mSecurityController.getDeviceOwnerOrganizationName());
+    }
+}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 45f2ec7..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;
@@ -2659,6 +2667,422 @@
     // OS: O
     TEXT_LONGPRESS = 629;
 
+    // ACTION: An app requested an unknown permission
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_UNKNOWN = 630;
+
+    // ACTION: An app was granted an unknown permission
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_UNKNOWN = 631;
+
+    // ACTION: An app requested an unknown permission and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_UNKNOWN = 632;
+
+    // ACTION: An unknown permission was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_UNKNOWN = 633;
+
+    // ACTION: An app requested the permission READ_CALENDAR
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_READ_CALENDAR = 634;
+
+    // ACTION: An app was granted the permission READ_CALENDAR
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_READ_CALENDAR = 635;
+
+    // ACTION: An app requested the permission READ_CALENDAR and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_READ_CALENDAR = 636;
+
+    // ACTION: The permission READ_CALENDAR was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_READ_CALENDAR = 637;
+
+    // ACTION: An app requested the permission WRITE_CALENDAR
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_WRITE_CALENDAR = 638;
+
+    // ACTION: An app was granted the permission WRITE_CALENDAR
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_WRITE_CALENDAR = 639;
+
+    // ACTION: An app requested the permission WRITE_CALENDAR and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_WRITE_CALENDAR = 640;
+
+    // ACTION: The permission WRITE_CALENDAR was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_WRITE_CALENDAR = 641;
+
+    // ACTION: An app requested the permission CAMERA
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_CAMERA = 642;
+
+    // ACTION: An app was granted the permission CAMERA
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_CAMERA = 643;
+
+    // ACTION: An app requested the permission CAMERA and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_CAMERA = 644;
+
+    // ACTION: The permission CAMERA was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_CAMERA = 645;
+
+    // ACTION: An app requested the permission READ_CONTACTS
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_READ_CONTACTS = 646;
+
+    // ACTION: An app was granted the permission READ_CONTACTS
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_READ_CONTACTS = 647;
+
+    // ACTION: An app requested the permission READ_CONTACTS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_READ_CONTACTS = 648;
+
+    // ACTION: The permission READ_CONTACTS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_READ_CONTACTS = 649;
+
+    // ACTION: An app requested the permission WRITE_CONTACTS
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_WRITE_CONTACTS = 650;
+
+    // ACTION: An app was granted the permission WRITE_CONTACTS
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_WRITE_CONTACTS = 651;
+
+    // ACTION: An app requested the permission WRITE_CONTACTS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_WRITE_CONTACTS = 652;
+
+    // ACTION: The permission WRITE_CONTACTS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_WRITE_CONTACTS = 653;
+
+    // ACTION: An app requested the permission GET_ACCOUNTS
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_GET_ACCOUNTS = 654;
+
+    // ACTION: An app was granted the permission GET_ACCOUNTS
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_GET_ACCOUNTS = 655;
+
+    // ACTION: An app requested the permission GET_ACCOUNTS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_GET_ACCOUNTS = 656;
+
+    // ACTION: The permission GET_ACCOUNTS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_GET_ACCOUNTS = 657;
+
+    // ACTION: An app requested the permission ACCESS_FINE_LOCATION
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_ACCESS_FINE_LOCATION = 658;
+
+    // ACTION: An app was granted the permission ACCESS_FINE_LOCATION
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_ACCESS_FINE_LOCATION = 659;
+
+    // ACTION: An app requested the permission ACCESS_FINE_LOCATION and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_ACCESS_FINE_LOCATION = 660;
+
+    // ACTION: The permission ACCESS_FINE_LOCATION was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_ACCESS_FINE_LOCATION = 661;
+
+    // ACTION: An app requested the permission ACCESS_COARSE_LOCATION
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_ACCESS_COARSE_LOCATION = 662;
+
+    // ACTION: An app was granted the permission ACCESS_COARSE_LOCATION
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_ACCESS_COARSE_LOCATION = 663;
+
+    // ACTION: An app requested the permission ACCESS_COARSE_LOCATION and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_ACCESS_COARSE_LOCATION = 664;
+
+    // ACTION: The permission ACCESS_COARSE_LOCATION was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_ACCESS_COARSE_LOCATION = 665;
+
+    // ACTION: An app requested the permission RECORD_AUDIO
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_RECORD_AUDIO = 666;
+
+    // ACTION: An app was granted the permission RECORD_AUDIO
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_RECORD_AUDIO = 667;
+
+    // ACTION: An app requested the permission RECORD_AUDIO and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_RECORD_AUDIO = 668;
+
+    // ACTION: The permission RECORD_AUDIO was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_RECORD_AUDIO = 669;
+
+    // ACTION: An app requested the permission READ_PHONE_STATE
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_READ_PHONE_STATE = 670;
+
+    // ACTION: An app was granted the permission READ_PHONE_STATE
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_READ_PHONE_STATE = 671;
+
+    // ACTION: An app requested the permission READ_PHONE_STATE and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_READ_PHONE_STATE = 672;
+
+    // ACTION: The permission READ_PHONE_STATE was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_READ_PHONE_STATE = 673;
+
+    // ACTION: An app requested the permission CALL_PHONE
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_CALL_PHONE = 674;
+
+    // ACTION: An app was granted the permission CALL_PHONE
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_CALL_PHONE = 675;
+
+    // ACTION: An app requested the permission CALL_PHONE and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_CALL_PHONE = 676;
+
+    // ACTION: The permission CALL_PHONE was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_CALL_PHONE = 677;
+
+    // ACTION: An app requested the permission READ_CALL_LOG
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_READ_CALL_LOG = 678;
+
+    // ACTION: An app was granted the permission READ_CALL_LOG
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_READ_CALL_LOG = 679;
+
+    // ACTION: An app requested the permission READ_CALL_LOG and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_READ_CALL_LOG = 680;
+
+    // ACTION: The permission READ_CALL_LOG was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_READ_CALL_LOG = 681;
+
+    // ACTION: An app requested the permission WRITE_CALL_LOG
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_WRITE_CALL_LOG = 682;
+
+    // ACTION: An app was granted the permission WRITE_CALL_LOG
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_WRITE_CALL_LOG = 683;
+
+    // ACTION: An app requested the permission WRITE_CALL_LOG and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_WRITE_CALL_LOG = 684;
+
+    // ACTION: The permission WRITE_CALL_LOG was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_WRITE_CALL_LOG = 685;
+
+    // ACTION: An app requested the permission ADD_VOICEMAIL
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_ADD_VOICEMAIL = 686;
+
+    // ACTION: An app was granted the permission ADD_VOICEMAIL
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_ADD_VOICEMAIL = 687;
+
+    // ACTION: An app requested the permission ADD_VOICEMAIL and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_ADD_VOICEMAIL = 688;
+
+    // ACTION: The permission ADD_VOICEMAIL was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_ADD_VOICEMAIL = 689;
+
+    // ACTION: An app requested the permission USE_SIP
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_USE_SIP = 690;
+
+    // ACTION: An app was granted the permission USE_SIP
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_USE_SIP = 691;
+
+    // ACTION: An app requested the permission USE_SIP and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_USE_SIP = 692;
+
+    // ACTION: The permission USE_SIP was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_USE_SIP = 693;
+
+    // ACTION: An app requested the permission PROCESS_OUTGOING_CALLS
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_PROCESS_OUTGOING_CALLS = 694;
+
+    // ACTION: An app was granted the permission PROCESS_OUTGOING_CALLS
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_PROCESS_OUTGOING_CALLS = 695;
+
+    // ACTION: An app requested the permission PROCESS_OUTGOING_CALLS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_PROCESS_OUTGOING_CALLS = 696;
+
+    // ACTION: The permission PROCESS_OUTGOING_CALLS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_PROCESS_OUTGOING_CALLS = 697;
+
+    // ACTION: An app requested the permission READ_CELL_BROADCASTS
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_READ_CELL_BROADCASTS = 698;
+
+    // ACTION: An app was granted the permission READ_CELL_BROADCASTS
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_READ_CELL_BROADCASTS = 699;
+
+    // ACTION: An app requested the permission READ_CELL_BROADCASTS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_READ_CELL_BROADCASTS = 700;
+
+    // ACTION: The permission READ_CELL_BROADCASTS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_READ_CELL_BROADCASTS = 701;
+
+    // ACTION: An app requested the permission BODY_SENSORS
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_BODY_SENSORS = 702;
+
+    // ACTION: An app was granted the permission BODY_SENSORS
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_BODY_SENSORS = 703;
+
+    // ACTION: An app requested the permission BODY_SENSORS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_BODY_SENSORS = 704;
+
+    // ACTION: The permission BODY_SENSORS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_BODY_SENSORS = 705;
+
+    // ACTION: An app requested the permission SEND_SMS
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_SEND_SMS = 706;
+
+    // ACTION: An app was granted the permission SEND_SMS
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_SEND_SMS = 707;
+
+    // ACTION: An app requested the permission SEND_SMS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_SEND_SMS = 708;
+
+    // ACTION: The permission SEND_SMS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_SEND_SMS = 709;
+
+    // ACTION: An app requested the permission RECEIVE_SMS
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_RECEIVE_SMS = 710;
+
+    // ACTION: An app was granted the permission RECEIVE_SMS
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_RECEIVE_SMS = 711;
+
+    // ACTION: An app requested the permission RECEIVE_SMS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_RECEIVE_SMS = 712;
+
+    // ACTION: The permission RECEIVE_SMS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_RECEIVE_SMS = 713;
+
+    // ACTION: An app requested the permission READ_SMS
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_READ_SMS = 714;
+
+    // ACTION: An app was granted the permission READ_SMS
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_READ_SMS = 715;
+
+    // ACTION: An app requested the permission READ_SMS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_READ_SMS = 716;
+
+    // ACTION: The permission READ_SMS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_READ_SMS = 717;
+
+    // ACTION: An app requested the permission RECEIVE_WAP_PUSH
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_RECEIVE_WAP_PUSH = 718;
+
+    // ACTION: An app was granted the permission RECEIVE_WAP_PUSH
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_RECEIVE_WAP_PUSH = 719;
+
+    // ACTION: An app requested the permission RECEIVE_WAP_PUSH and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_RECEIVE_WAP_PUSH = 720;
+
+    // ACTION: The permission RECEIVE_WAP_PUSH was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_RECEIVE_WAP_PUSH = 721;
+
+    // ACTION: An app requested the permission RECEIVE_MMS
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_RECEIVE_MMS = 722;
+
+    // ACTION: An app was granted the permission RECEIVE_MMS
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_RECEIVE_MMS = 723;
+
+    // ACTION: An app requested the permission RECEIVE_MMS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_RECEIVE_MMS = 724;
+
+    // ACTION: The permission RECEIVE_MMS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_RECEIVE_MMS = 725;
+
+    // ACTION: An app requested the permission READ_EXTERNAL_STORAGE
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 726;
+
+    // ACTION: An app was granted the permission READ_EXTERNAL_STORAGE
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_READ_EXTERNAL_STORAGE = 727;
+
+    // ACTION: An app requested the permission READ_EXTERNAL_STORAGE and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_READ_EXTERNAL_STORAGE = 728;
+
+    // ACTION: The permission READ_EXTERNAL_STORAGE was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_READ_EXTERNAL_STORAGE = 729;
+
+    // ACTION: An app requested the permission WRITE_EXTERNAL_STORAGE
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 730;
+
+    // ACTION: An app was granted the permission WRITE_EXTERNAL_STORAGE
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_PERMISSION_GRANT_WRITE_EXTERNAL_STORAGE = 731;
+
+    // ACTION: An app requested the permission WRITE_EXTERNAL_STORAGE and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_PERMISSION_DENIED_WRITE_EXTERNAL_STORAGE = 732;
+
+    // ACTION: The permission WRITE_EXTERNAL_STORAGE was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_PERMISSION_REVOKE_WRITE_EXTERNAL_STORAGE = 733;
+
     // ---- End O Constants, all O constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 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/Android.mk b/services/core/Android.mk
index 88a8385..efadbef 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -12,6 +12,7 @@
     java/com/android/server/am/EventLogTags.logtags \
     ../../../../system/netd/server/binder/android/net/INetd.aidl \
     ../../../../system/netd/server/binder/android/net/metrics/INetdEventListener.aidl \
+    ../../../native/cmds/installd/binder/android/os/IInstalld.aidl \
 
 LOCAL_AIDL_INCLUDES += \
     system/netd/server/binder
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 c8ed872..6aa0dc9 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -21,8 +21,9 @@
 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;
 import com.android.internal.telephony.TelephonyIntents;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
@@ -199,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;
@@ -270,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;
@@ -359,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;
@@ -2879,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);
+        }
     }
 
     /**
@@ -3690,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);
 
@@ -8509,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);
 
@@ -9172,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;
                         }
                     }
@@ -9597,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) {
@@ -9826,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();
@@ -9843,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);
@@ -10028,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();
@@ -10073,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);
@@ -14427,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) {
             }
         }
@@ -15404,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;
                 }
@@ -18834,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();
@@ -19112,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);
@@ -22127,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);
         }
@@ -22542,6 +22563,17 @@
         return rInfo != null && rInfo.activityInfo != null;
     }
 
+    @Override
+    public void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback)
+            throws RemoteException {
+        final long callingId = Binder.clearCallingIdentity();
+        try {
+            mKeyguardController.dismissKeyguard(token, callback);
+        } finally {
+            Binder.restoreCallingIdentity(callingId);
+        }
+    }
+
     /**
      * Attach an agent to the specified process (proces name or PID)
      */
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 90b46ed..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;
@@ -207,6 +209,8 @@
     boolean keysPaused;     // has key dispatching been paused for it?
     int launchMode;         // the launch mode activity attribute.
     boolean visible;        // does this activity's window need to be shown?
+    boolean visibleIgnoringKeyguard; // is this activity visible, ignoring the fact that Keyguard
+                                     // might hide this activity?
     boolean sleeping;       // have we told the activity to sleep?
     boolean nowVisible;     // is this activity's window visible?
     boolean idle;           // has the activity gone idle?
@@ -1195,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;
         }
 
@@ -1248,9 +1253,15 @@
         mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
     }
 
-    /** Return true if the input activity should be made visible */
-    boolean shouldBeVisible(boolean behindTranslucentActivity, boolean stackVisibleBehind,
-            ActivityRecord visibleBehind, boolean behindFullscreenActivity) {
+    /**
+     * @return true if the input activity should be made visible, ignoring any effect Keyguard
+     * might have on the visibility
+     *
+     * @see {@link ActivityStack#checkKeyguardVisibility}
+     */
+    boolean shouldBeVisibleIgnoringKeyguard(boolean behindTranslucentActivity,
+            boolean stackVisibleBehind, ActivityRecord visibleBehind,
+            boolean behindFullscreenActivity) {
         if (!okToShowLocked()) {
             return false;
         }
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 473b1a3..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;
         }
 
@@ -1660,13 +1665,15 @@
                     aboveTop = false;
 
                     // Check whether activity should be visible without Keyguard influence
-                    final boolean shouldBeVisible = r.shouldBeVisible(behindTranslucentActivity,
-                            stackVisibleBehind, visibleBehind, behindFullscreenActivity);
+                    final boolean visibleIgnoringKeyguard = r.shouldBeVisibleIgnoringKeyguard(
+                            behindTranslucentActivity, stackVisibleBehind, visibleBehind,
+                            behindFullscreenActivity);
+                    r.visibleIgnoringKeyguard = visibleIgnoringKeyguard;
 
                     // Now check whether it's really visible depending on Keyguard state.
-                    final boolean reallyVisible = checkKeyguardVisibility(r, shouldBeVisible,
-                            isTop);
-                    if (shouldBeVisible) {
+                    final boolean reallyVisible = checkKeyguardVisibility(r,
+                            visibleIgnoringKeyguard, isTop);
+                    if (visibleIgnoringKeyguard) {
                         behindFullscreenActivity = updateBehindFullscreen(stackInvisible,
                                 behindFullscreenActivity, task, r);
                         if (behindFullscreenActivity && !r.fullscreen) {
@@ -1823,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;
         }
@@ -1920,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);
@@ -2094,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(
@@ -2110,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;
@@ -2145,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");
             }
         }
 
@@ -2565,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) {
@@ -2574,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;
                 }
@@ -2673,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.
@@ -3112,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;
                     }
@@ -3135,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) {
@@ -3144,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);
@@ -3752,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);
         }
@@ -4174,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);
@@ -4304,7 +4304,7 @@
                 moveToBack(topTask());
 
                 // Resume an activity in the next focusable stack.
-                adjustFocusToNextFocusableStackLocked(APPLICATION_ACTIVITY_TYPE, "moveTaskToBack");
+                adjustFocusToNextFocusableStackLocked("moveTaskToBack");
                 mStackSupervisor.resumeFocusedStackTopActivityLocked();
                 return true;
             }
@@ -4363,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();
@@ -4838,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);
                 }
             }
@@ -4848,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 5d8d79f..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(
@@ -3779,6 +3774,7 @@
             findTaskToMoveToFrontLocked(task, 0, null, reason,
                     lockTaskModeState != LOCK_TASK_MODE_NONE);
             resumeFocusedStackTopActivityLocked();
+            mWindowManager.executeAppTransition();
         } else if (lockTaskModeState != LOCK_TASK_MODE_NONE) {
             handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, task.getStackId(),
                     true /* forceNonResizable */);
@@ -4075,7 +4071,7 @@
                                     Settings.Secure.LOCK_TO_APP_EXIT_LOCKED) != 0;
                             if (mLockTaskModeState == LOCK_TASK_MODE_PINNED && shouldLockKeyguard) {
                                 mWindowManager.lockNow(null);
-                                mWindowManager.dismissKeyguard();
+                                mWindowManager.dismissKeyguard(null /* callback */);
                                 new LockPatternUtils(mService.mContext)
                                         .requireCredentialEntry(UserHandle.USER_ALL);
                             }
@@ -4591,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/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 7a122e6..029b5dd 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -300,15 +300,19 @@
      * @param crashInfo describing the failure
      */
     void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
+        final int callingPid = Binder.getCallingPid();
+        final int callingUid = Binder.getCallingUid();
+
         final long origId = Binder.clearCallingIdentity();
         try {
-            crashApplicationInner(r, crashInfo);
+            crashApplicationInner(r, crashInfo, callingPid, callingUid);
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
     }
 
-    void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
+    void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo,
+            int callingPid, int callingUid) {
         long timeMillis = System.currentTimeMillis();
         String shortMsg = crashInfo.exceptionClassName;
         String longMsg = crashInfo.exceptionMessage;
@@ -327,7 +331,7 @@
              * finish now and don't show the app error dialog.
              */
             if (handleAppCrashInActivityController(r, crashInfo, shortMsg, longMsg, stackTrace,
-                    timeMillis)) {
+                    timeMillis, callingPid, callingUid)) {
                 return;
             }
 
@@ -429,15 +433,16 @@
     private boolean handleAppCrashInActivityController(ProcessRecord r,
                                                        ApplicationErrorReport.CrashInfo crashInfo,
                                                        String shortMsg, String longMsg,
-                                                       String stackTrace, long timeMillis) {
+                                                       String stackTrace, long timeMillis,
+                                                       int callingPid, int callingUid) {
         if (mService.mController == null) {
             return false;
         }
 
         try {
             String name = r != null ? r.processName : null;
-            int pid = r != null ? r.pid : Binder.getCallingPid();
-            int uid = r != null ? r.info.uid : Binder.getCallingUid();
+            int pid = r != null ? r.pid : callingPid;
+            int uid = r != null ? r.info.uid : callingUid;
             if (!mService.mController.appCrashed(name, pid,
                     shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
                 if ("1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"))
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 9d8c383..19bf536 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -20,6 +20,8 @@
 import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
 import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
 import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
+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.ActivityStackSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
 import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
@@ -29,6 +31,11 @@
 import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_UNOCCLUDE;
 import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
 
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.server.wm.WindowManagerService;
 
 import java.io.PrintWriter;
@@ -42,12 +49,15 @@
  */
 class KeyguardController {
 
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_AM;
+
     private final ActivityManagerService mService;
     private final ActivityStackSupervisor mStackSupervisor;
     private WindowManagerService mWindowManager;
     private boolean mKeyguardShowing;
     private boolean mKeyguardGoingAway;
     private boolean mOccluded;
+    private boolean mDismissalRequested;
     private ActivityRecord mDismissingKeyguardActivity;
     private int mBeforeUnoccludeTransit;
     private int mVisibilityTransactionDepth;
@@ -86,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();
@@ -108,7 +116,6 @@
                 mWindowManager.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
                         false /* alwaysKeepCurrent */, convertTransitFlags(flags),
                         false /* forceOverride */);
-                mWindowManager.keyguardGoingAway(flags);
                 mService.updateSleepIfNeededLocked();
 
                 // Some stack visibility might change (e.g. docked stack)
@@ -122,6 +129,23 @@
         }
     }
 
+    void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback) {
+        final ActivityRecord activityRecord = ActivityRecord.forTokenLocked(token);
+        if (activityRecord == null || !activityRecord.visibleIgnoringKeyguard) {
+            failCallback(callback);
+            return;
+        }
+        mWindowManager.dismissKeyguard(callback);
+    }
+
+    private void failCallback(IKeyguardDismissCallback callback) {
+        try {
+            callback.onDismissError();
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Failed to call callback", e);
+        }
+    }
+
     private int convertTransitFlags(int keyguardGoingAwayFlags) {
         int result = 0;
         if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_TO_SHADE) != 0) {
@@ -158,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() {
@@ -174,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) {
@@ -214,8 +257,13 @@
      * Called when somebody might want to dismiss the Keyguard.
      */
     private void handleDismissKeyguard() {
-        if (mDismissingKeyguardActivity != null) {
-            mWindowManager.dismissKeyguard();
+        // 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.
@@ -271,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/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index ac9545c..67f3614 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -139,7 +139,9 @@
  *
  * @hide
  */
-public class AudioService extends IAudioService.Stub {
+public class AudioService extends IAudioService.Stub
+        implements AccessibilityManager.TouchExplorationStateChangeListener,
+            AccessibilityManager.AccessibilityStateChangeListener{
 
     private static final String TAG = "AudioService";
 
@@ -775,7 +777,7 @@
                 TAG,
                 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
 
-        StreamOverride.init(mContext);
+        initA11yMonitoring(mContext);
         mControllerService.init();
         onIndicateSystemReady();
     }
@@ -972,6 +974,8 @@
 
     private void updateStreamVolumeAlias(boolean updateVolumes, String caller) {
         int dtmfStreamAlias;
+        final int a11yStreamAlias = sIndependentA11yVolume ?
+                AudioSystem.STREAM_ACCESSIBILITY : AudioSystem.STREAM_MUSIC;
 
         if (mIsSingleVolume) {
             mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
@@ -1000,9 +1004,13 @@
         }
 
         mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
+        mStreamVolumeAlias[AudioSystem.STREAM_ACCESSIBILITY] = a11yStreamAlias;
+
         if (updateVolumes) {
             mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
                     caller);
+            mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].setAllIndexes(
+                    mStreamStates[a11yStreamAlias], caller);
             // apply stream mute states according to new value of mRingerModeAffectedStreams
             setRingerModeInt(getRingerModeInternal(), false);
             sendMsg(mAudioHandler,
@@ -1011,6 +1019,12 @@
                     0,
                     0,
                     mStreamStates[AudioSystem.STREAM_DTMF], 0);
+            sendMsg(mAudioHandler,
+                    MSG_SET_ALL_VOLUMES,
+                    SENDMSG_QUEUE,
+                    0,
+                    0,
+                    mStreamStates[AudioSystem.STREAM_ACCESSIBILITY], 0);
         }
     }
 
@@ -1536,6 +1550,10 @@
 
     private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
             String caller, int uid) {
+        if (DEBUG_VOL) {
+            Log.d(TAG, "setStreamVolume(stream=" + streamType+", index=" + index
+                    + ", calling=" + callingPackage + ")");
+        }
         if (mUseFixedVolume) {
             return;
         }
@@ -3639,7 +3657,7 @@
                     return AudioSystem.STREAM_VOICE_CALL;
                 }
             } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
-                if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
+                if (isAfMusicActiveRecently(sStreamOverrideDelayMs)) {
                     if (DEBUG_VOL)
                         Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
                     return AudioSystem.STREAM_MUSIC;
@@ -3665,13 +3683,13 @@
                     return AudioSystem.STREAM_VOICE_CALL;
                 }
             } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
-                    StreamOverride.sDelayMs) ||
+                    sStreamOverrideDelayMs) ||
                     AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
-                            StreamOverride.sDelayMs)) {
+                            sStreamOverrideDelayMs)) {
                 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
                 return AudioSystem.STREAM_NOTIFICATION;
             } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
-                if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
+                if (isAfMusicActiveRecently(sStreamOverrideDelayMs)) {
                     if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
                     return AudioSystem.STREAM_MUSIC;
                 } else {
@@ -5861,44 +5879,67 @@
     }
 
     //==========================================================================================
-    // Accessibility: taking touch exploration into account for selecting the default
+    // Accessibility
+
+    private void initA11yMonitoring(Context ctxt) {
+        AccessibilityManager accessibilityManager =
+                (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
+        updateDefaultStreamOverrideDelay(accessibilityManager.isTouchExplorationEnabled());
+        updateA11yVolumeAlias(accessibilityManager.isEnabled());
+        accessibilityManager.addTouchExplorationStateChangeListener(this);
+        accessibilityManager.addAccessibilityStateChangeListener(this);
+    }
+
+    //---------------------------------------------------------------------------------
+    // A11y: taking touch exploration into account for selecting the default
     //   stream override timeout when adjusting volume
-    //==========================================================================================
-    private static class StreamOverride
-            implements AccessibilityManager.TouchExplorationStateChangeListener {
+    //---------------------------------------------------------------------------------
 
-        // AudioService.getActiveStreamType() will return:
-        // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
-        // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
-        // stopped
-        private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 0;
-        private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
+    // AudioService.getActiveStreamType() will return:
+    // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
+    // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
+    // stopped
+    private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 0;
+    private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
 
-        static int sDelayMs;
+    private static int sStreamOverrideDelayMs;
 
-        static void init(Context ctxt) {
-            AccessibilityManager accessibilityManager =
-                    (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
-            updateDefaultStreamOverrideDelay(
-                    accessibilityManager.isTouchExplorationEnabled());
-            accessibilityManager.addTouchExplorationStateChangeListener(
-                    new StreamOverride());
+    @Override
+    public void onTouchExplorationStateChanged(boolean enabled) {
+        updateDefaultStreamOverrideDelay(enabled);
+    }
+
+    private void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
+        if (touchExploreEnabled) {
+            sStreamOverrideDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
+        } else {
+            sStreamOverrideDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
         }
+        if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
+                + " stream override delay is now " + sStreamOverrideDelayMs + " ms");
+    }
 
-        @Override
-        public void onTouchExplorationStateChanged(boolean enabled) {
-            updateDefaultStreamOverrideDelay(enabled);
-        }
+    //---------------------------------------------------------------------------------
+    // A11y: taking a11y state into account for the handling of a11y prompts volume
+    //---------------------------------------------------------------------------------
 
-        private static void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
-            if (touchExploreEnabled) {
-                sDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
-            } else {
-                sDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
-            }
-            if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
-                    + " stream override delay is now " + sDelayMs + " ms");
-        }
+    private static boolean sIndependentA11yVolume = false;
+
+    @Override
+    public void onAccessibilityStateChanged(boolean enabled) {
+        updateA11yVolumeAlias(enabled);
+    }
+
+    private void updateA11yVolumeAlias(boolean a11Enabled) {
+        if (DEBUG_VOL) Log.d(TAG, "Accessibility mode changed to " + a11Enabled);
+        // a11y has its own volume stream when a11y service is enabled
+        sIndependentA11yVolume = a11Enabled;
+        // update the volume mapping scheme
+        updateStreamVolumeAlias(true /*updateVolumes*/, TAG);
+        // update the volume controller behavior
+        mVolumeController.setA11yMode(sIndependentA11yVolume ?
+                VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME :
+                    VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME);
     }
 
     //==========================================================================================
@@ -6178,6 +6219,16 @@
                 Log.w(TAG, "Error calling dismiss", e);
             }
         }
+
+        public void setA11yMode(int a11yMode) {
+            if (mController == null)
+                return;
+            try {
+                mController.setA11yMode(a11yMode);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Error calling setA11Mode", e);
+            }
+        }
     }
 
     /**
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/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 273bc64..132967c 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -32,11 +32,14 @@
 import android.content.pm.UserInfo;
 import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.DeadObjectException;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.IRemoteCallback;
 import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
 import android.os.RemoteException;
 import android.os.SELinux;
 import android.os.ServiceManager;
@@ -625,17 +628,28 @@
 
     private class FingerprintServiceLockoutResetMonitor {
 
+        private static final long WAKELOCK_TIMEOUT_MS = 2000;
         private final IFingerprintServiceLockoutResetCallback mCallback;
+        private final WakeLock mWakeLock;
 
         public FingerprintServiceLockoutResetMonitor(
                 IFingerprintServiceLockoutResetCallback callback) {
             mCallback = callback;
+            mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+                    "lockout reset callback");
         }
 
         public void sendLockoutReset() {
             if (mCallback != null) {
                 try {
-                    mCallback.onLockoutReset(mHalDeviceId);
+                    mWakeLock.acquire(WAKELOCK_TIMEOUT_MS);
+                    mCallback.onLockoutReset(mHalDeviceId, new IRemoteCallback.Stub() {
+
+                        @Override
+                        public void sendResult(Bundle data) throws RemoteException {
+                            mWakeLock.release();
+                        }
+                    });
                 } catch (DeadObjectException e) {
                     Slog.w(TAG, "Death object while invoking onLockoutReset: ", e);
                     mHandler.post(mRemoveCallbackRunnable);
@@ -648,6 +662,9 @@
         private final Runnable mRemoveCallbackRunnable = new Runnable() {
             @Override
             public void run() {
+                if (mWakeLock.isHeld()) {
+                    mWakeLock.release();
+                }
                 removeLockoutResetCallback(FingerprintServiceLockoutResetMonitor.this);
             }
         };
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/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 2e18b1c..3dc8f54 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -20,6 +20,10 @@
 import android.content.Context;
 import android.content.pm.PackageStats;
 import android.os.Build;
+import android.os.IInstalld;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
 import android.util.Slog;
 
 import com.android.internal.os.InstallerConnection;
@@ -33,6 +37,8 @@
 public final class Installer extends SystemService {
     private static final String TAG = "Installer";
 
+    private static final boolean USE_BINDER = true;
+
     /* ***************************************************************************
      * IMPORTANT: These values are passed to native code. Keep them in sync with
      * frameworks/native/cmds/installd/installd.h
@@ -55,10 +61,13 @@
     public static final int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
 
     private final InstallerConnection mInstaller;
+    private final IInstalld mInstalld;
 
     public Installer(Context context) {
         super(context);
         mInstaller = new InstallerConnection();
+        // TODO: reconnect if installd restarts
+        mInstalld = IInstalld.Stub.asInterface(ServiceManager.getService("installd"));
     }
 
     // Package-private installer that accepts a custom InstallerConnection. Used for
@@ -66,6 +75,8 @@
     Installer(Context context, InstallerConnection connection) {
         super(context);
         mInstaller = connection;
+        // TODO: reconnect if installd restarts
+        mInstalld = IInstalld.Stub.asInterface(ServiceManager.getService("installd"));
     }
 
     /**
@@ -84,8 +95,17 @@
 
     public void createAppData(String uuid, String pkgname, int userid, int flags, int appid,
             String seinfo, int targetSdkVersion) throws InstallerException {
-        mInstaller.execute("create_app_data", uuid, pkgname, userid, flags, appid, seinfo,
-            targetSdkVersion);
+        if (USE_BINDER) {
+            try {
+                mInstalld.createAppData(uuid, pkgname, userid, flags, appid, seinfo,
+                        targetSdkVersion);
+            } catch (RemoteException | ServiceSpecificException e) {
+                throw new InstallerException(e.getMessage());
+            }
+        } else {
+            mInstaller.execute("create_app_data", uuid, pkgname, userid, flags, appid, seinfo,
+                    targetSdkVersion);
+        }
     }
 
     public void restoreconAppData(String uuid, String pkgname, int userid, int flags, int appid,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c1bc618..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,7 +102,9 @@
 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;
 import android.app.ResourcesManager;
 import android.app.admin.IDevicePolicyManager;
@@ -231,6 +235,7 @@
 import com.android.internal.content.NativeLibraryHelper;
 import com.android.internal.content.PackageHelper;
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.os.IParcelFileDescriptorFactory;
 import com.android.internal.os.InstallerConnection.InstallerException;
 import com.android.internal.os.RoSystemProperties;
@@ -402,8 +407,8 @@
     static final int SCAN_CHECK_ONLY = 1<<13;
     static final int SCAN_DONT_KILL_APP = 1<<14;
     static final int SCAN_IGNORE_FROZEN = 1<<15;
-
     static final int REMOVE_CHATTY = 1<<16;
+    static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1<<17;
 
     private static final int[] EMPTY_INT_ARRAY = new int[0];
 
@@ -527,6 +532,34 @@
     /** Special library name that skips shared libraries check during compilation. */
     private static final String SKIP_SHARED_LIBRARY_CHECK = "&";
 
+    /** All dangerous permission names in the same order as the events in MetricsEvent */
+    private static final List<String> ALL_DANGEROUS_PERMISSIONS = Arrays.asList(
+            Manifest.permission.READ_CALENDAR,
+            Manifest.permission.WRITE_CALENDAR,
+            Manifest.permission.CAMERA,
+            Manifest.permission.READ_CONTACTS,
+            Manifest.permission.WRITE_CONTACTS,
+            Manifest.permission.GET_ACCOUNTS,
+            Manifest.permission.ACCESS_FINE_LOCATION,
+            Manifest.permission.ACCESS_COARSE_LOCATION,
+            Manifest.permission.RECORD_AUDIO,
+            Manifest.permission.READ_PHONE_STATE,
+            Manifest.permission.CALL_PHONE,
+            Manifest.permission.READ_CALL_LOG,
+            Manifest.permission.WRITE_CALL_LOG,
+            Manifest.permission.ADD_VOICEMAIL,
+            Manifest.permission.USE_SIP,
+            Manifest.permission.PROCESS_OUTGOING_CALLS,
+            Manifest.permission.READ_CELL_BROADCASTS,
+            Manifest.permission.BODY_SENSORS,
+            Manifest.permission.SEND_SMS,
+            Manifest.permission.RECEIVE_SMS,
+            Manifest.permission.READ_SMS,
+            Manifest.permission.RECEIVE_WAP_PUSH,
+            Manifest.permission.RECEIVE_MMS,
+            Manifest.permission.READ_EXTERNAL_STORAGE,
+            Manifest.permission.WRITE_EXTERNAL_STORAGE);
+
     final ServiceThread mHandlerThread;
 
     final PackageHandler mHandler;
@@ -744,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();
 
@@ -2215,10 +2246,6 @@
             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
                     startTime);
 
-            // Set flag to monitor and not change apk file paths when
-            // scanning install directories.
-            final int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
-
             final String bootClassPath = System.getenv("BOOTCLASSPATH");
             final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");
 
@@ -2303,6 +2330,14 @@
                 }
             }
 
+            // Set flag to monitor and not change apk file paths when
+            // scanning install directories.
+            int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
+
+            if (mIsUpgrade || mFirstBoot) {
+                scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
+            }
+
             // Collect vendor overlay packages. (Do this before scanning any apps.)
             // For security and version matching reason, only consider
             // overlay packages if they reside in the right directory.
@@ -2706,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)
@@ -2923,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) {
@@ -3106,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);
     }
@@ -3187,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);
             }
@@ -3234,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);
@@ -3258,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);
@@ -3384,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);
             }
         }
@@ -3493,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) {
@@ -3509,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());
@@ -4132,6 +4189,10 @@
                 break;
             }
 
+            if (bp.isRuntime()) {
+                logPermissionGranted(mContext, name, packageName);
+            }
+
             mOnPermissionChangeListeners.onPermissionsChanged(uid);
 
             // Not critical if that is lost - app has to request again.
@@ -4233,6 +4294,10 @@
                 return;
             }
 
+            if (bp.isRuntime()) {
+                logPermissionRevoked(mContext, name, packageName);
+            }
+
             mOnPermissionChangeListeners.onPermissionsChanged(pkg.applicationInfo.uid);
 
             // Critical, after this call app should never have the permission.
@@ -4244,6 +4309,66 @@
         killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);
     }
 
+    /**
+     * Get the first event id for the permission.
+     *
+     * <p>There are four events for each permission: <ul>
+     *     <li>Request permission: first id + 0</li>
+     *     <li>Grant permission: first id + 1</li>
+     *     <li>Request for permission denied: first id + 2</li>
+     *     <li>Revoke permission: first id + 3</li>
+     * </ul></p>
+     *
+     * @param name name of the permission
+     *
+     * @return The first event id for the permission
+     */
+    private static int getBaseEventId(@NonNull String name) {
+        int eventIdIndex = ALL_DANGEROUS_PERMISSIONS.indexOf(name);
+
+        if (eventIdIndex == -1) {
+            if (AppOpsManager.permissionToOpCode(name) == AppOpsManager.OP_NONE
+                    || "user".equals(Build.TYPE)) {
+                Log.i(TAG, "Unknown permission " + name);
+
+                return MetricsEvent.ACTION_PERMISSION_REQUEST_UNKNOWN;
+            } else {
+                // Most likely #ALL_DANGEROUS_PERMISSIONS needs to be updated.
+                //
+                // Also update
+                // - EventLogger#ALL_DANGEROUS_PERMISSIONS
+                // - metrics_constants.proto
+                throw new IllegalStateException("Unknown permission " + name);
+            }
+        }
+
+        return MetricsEvent.ACTION_PERMISSION_REQUEST_READ_CALENDAR + eventIdIndex * 4;
+    }
+
+    /**
+     * Log that a permission was revoked.
+     *
+     * @param context Context of the caller
+     * @param name name of the permission
+     * @param packageName package permission if for
+     */
+    private static void logPermissionRevoked(@NonNull Context context, @NonNull String name,
+            @NonNull String packageName) {
+        MetricsLogger.action(context, getBaseEventId(name) + 3, packageName);
+    }
+
+    /**
+     * Log that a permission request was granted.
+     *
+     * @param context Context of the caller
+     * @param name name of the permission
+     * @param packageName package permission if for
+     */
+    private static void logPermissionGranted(@NonNull Context context, @NonNull String name,
+            @NonNull String packageName) {
+        MetricsLogger.action(context, getBaseEventId(name) + 1, packageName);
+    }
+
     @Override
     public void resetRuntimePermissions() {
         mContext.enforceCallingOrSelfPermission(
@@ -4917,6 +5042,9 @@
         if (mEphemeralResolverConnection == null) {
             return false;
         }
+        if (mEphemeralInstallerComponent == null) {
+            return false;
+        }
         if (intent.getComponent() != null) {
             return false;
         }
@@ -6194,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");
@@ -6278,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) {
@@ -6286,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()) {
@@ -6306,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) {
@@ -6315,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);
@@ -8082,6 +8219,11 @@
         // old setting to restore at the end.
         PackageSetting nonMutatedPs = null;
 
+        // We keep references to the derived CPU Abis from settings in oder to reuse
+        // them in the case where we're not upgrading or booting for the first time.
+        String primaryCpuAbiFromSettings = null;
+        String secondaryCpuAbiFromSettings = null;
+
         // writer
         synchronized (mPackages) {
             if (pkg.mSharedUserId != null) {
@@ -8158,6 +8300,14 @@
                 }
             }
 
+            if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) == 0) {
+                PackageSetting foundPs = mSettings.getPackageLPr(pkg.packageName);
+                if (foundPs != null) {
+                    primaryCpuAbiFromSettings = foundPs.primaryCpuAbiString;
+                    secondaryCpuAbiFromSettings = foundPs.secondaryCpuAbiString;
+                }
+            }
+
             pkgSetting = mSettings.getPackageLPr(pkg.packageName);
             if (pkgSetting != null && pkgSetting.sharedUser != suid) {
                 PackageManagerService.reportSettingsProblem(Log.WARN,
@@ -8190,7 +8340,11 @@
                 }
                 mSettings.addUserToSettingLPw(pkgSetting);
             } else {
-                // REMOVE SharedUserSetting from method; update in a separate call
+                // REMOVE SharedUserSetting from method; update in a separate call.
+                //
+                // TODO(narayan): This update is bogus. nativeLibraryDir & primaryCpuAbi,
+                // secondaryCpuAbi are not known at this point so we always update them
+                // to null here, only to reset them at a later point.
                 Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, suid, destCodeFile,
                         pkg.applicationInfo.nativeLibraryDir, pkg.applicationInfo.primaryCpuAbi,
                         pkg.applicationInfo.secondaryCpuAbi, pkg.applicationInfo.flags,
@@ -8329,18 +8483,34 @@
         final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, pkgSetting);
 
         if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
-            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
-            derivePackageAbi(
-                    pkg, scanFile, cpuAbiOverride, true /*extractLibs*/, mAppLib32InstallDir);
-            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+            if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0) {
+                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
+                derivePackageAbi(
+                        pkg, scanFile, cpuAbiOverride, true /*extractLibs*/, mAppLib32InstallDir);
+                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
 
-            // Some system apps still use directory structure for native libraries
-            // in which case we might end up not detecting abi solely based on apk
-            // structure. Try to detect abi based on directory structure.
-            if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&
-                    pkg.applicationInfo.primaryCpuAbi == null) {
-                setBundledAppAbisAndRoots(pkg, pkgSetting);
+                // Some system apps still use directory structure for native libraries
+                // in which case we might end up not detecting abi solely based on apk
+                // structure. Try to detect abi based on directory structure.
+                if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&
+                        pkg.applicationInfo.primaryCpuAbi == null) {
+                    setBundledAppAbisAndRoots(pkg, pkgSetting);
+                    setNativeLibraryPaths(pkg, mAppLib32InstallDir);
+                }
+            } else {
+                // This is not a first boot or an upgrade, don't bother deriving the
+                // ABI during the scan. Instead, trust the value that was stored in the
+                // package setting.
+                pkg.applicationInfo.primaryCpuAbi = primaryCpuAbiFromSettings;
+                pkg.applicationInfo.secondaryCpuAbi = secondaryCpuAbiFromSettings;
+
                 setNativeLibraryPaths(pkg, mAppLib32InstallDir);
+
+                if (DEBUG_ABI_SELECTION) {
+                    Slog.i(TAG, "Using ABIS and native lib paths from settings : " +
+                        pkg.packageName + " " + pkg.applicationInfo.primaryCpuAbi + ", " +
+                        pkg.applicationInfo.secondaryCpuAbi);
+                }
             }
         } else {
             if ((scanFlags & SCAN_MOVE) != 0) {
@@ -8916,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);
@@ -8954,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;
 
@@ -9195,11 +9380,6 @@
                                  String cpuAbiOverride, boolean extractLibs,
                                  File appLib32InstallDir)
             throws PackageManagerException {
-        // TODO: We can probably be smarter about this stuff. For installed apps,
-        // we can calculate this information at install time once and for all. For
-        // system apps, we can probably assume that this information doesn't change
-        // after the first boot scan. As things stand, we do lots of unnecessary work.
-
         // Give ourselves some initial paths; we'll come back for another
         // pass once we've determined ABI below.
         setNativeLibraryPaths(pkg, appLib32InstallDir);
@@ -9458,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;
@@ -9477,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) {
@@ -10392,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/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 3ad2ae1..6089d2e 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -76,14 +76,12 @@
     String legacyNativeLibraryPathString;
 
     /**
-     * The primary CPU abi for this package. This value is regenerated at every
-     * boot scan.
+     * The primary CPU abi for this package.
      */
     String primaryCpuAbiString;
 
     /**
-     * The secondary CPU abi for this package. This value is regenerated at every
-     * boot scan.
+     * The secondary CPU abi for this package.
      */
     String secondaryCpuAbiString;
 
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 ccdda13..a1cce2b 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -216,6 +216,7 @@
 
 import com.android.internal.R;
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
 import com.android.internal.policy.PhoneWindow;
 import com.android.internal.statusbar.IStatusBarService;
@@ -264,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;
@@ -1344,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;
             }
         }
     }
@@ -6631,12 +6641,18 @@
     }
 
     @Override
-    public void dismissKeyguardLw() {
+    public void dismissKeyguardLw(IKeyguardDismissCallback callback) {
         if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
             if (DEBUG_KEYGUARD) Slog.d(TAG, "PWM.dismissKeyguardLw");
 
             // ask the keyguard to prompt the user to authenticate if necessary
-            mKeyguardDelegate.dismiss(true /* allowWhileOccluded */);
+            mKeyguardDelegate.dismiss(callback);
+        } else if (callback != null) {
+            try {
+                callback.onDismissError();
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed to call callback", e);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index f37f987..1b4eaf5 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -15,6 +15,7 @@
 import android.util.Slog;
 import android.view.WindowManagerPolicy.OnKeyguardExitResult;
 
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IKeyguardDrawnCallback;
 import com.android.internal.policy.IKeyguardExitCallback;
 import com.android.internal.policy.IKeyguardService;
@@ -244,9 +245,9 @@
         mKeyguardState.occluded = isOccluded;
     }
 
-    public void dismiss(boolean allowWhileOccluded) {
+    public void dismiss(IKeyguardDismissCallback callback) {
         if (mKeyguardService != null) {
-            mKeyguardService.dismiss(allowWhileOccluded);
+            mKeyguardService.dismiss(callback);
         }
     }
 
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index c4a0dd3..0b839b8 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -22,6 +22,7 @@
 import android.os.RemoteException;
 import android.util.Slog;
 
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IKeyguardDrawnCallback;
 import com.android.internal.policy.IKeyguardExitCallback;
 import com.android.internal.policy.IKeyguardService;
@@ -73,9 +74,9 @@
     }
 
     @Override // Binder interface
-    public void dismiss(boolean allowWhileOccluded) {
+    public void dismiss(IKeyguardDismissCallback callback) {
         try {
-            mService.dismiss(allowWhileOccluded);
+            mService.dismiss(callback);
         } catch (RemoteException e) {
             Slog.w(TAG , "Remote Exception", e);
         }
diff --git a/services/core/java/com/android/server/twilight/TwilightService.java b/services/core/java/com/android/server/twilight/TwilightService.java
index db7df25..bb4d67e 100644
--- a/services/core/java/com/android/server/twilight/TwilightService.java
+++ b/services/core/java/com/android/server/twilight/TwilightService.java
@@ -59,17 +59,17 @@
 
     private final Handler mHandler;
 
-    private AlarmManager mAlarmManager;
+    protected AlarmManager mAlarmManager;
     private LocationManager mLocationManager;
 
     private boolean mBootCompleted;
     private boolean mHasListeners;
 
     private BroadcastReceiver mTimeChangedReceiver;
-    private Location mLastLocation;
+    protected Location mLastLocation;
 
     @GuardedBy("mListeners")
-    private TwilightState mLastTwilightState;
+    protected TwilightState mLastTwilightState;
 
     public TwilightService(Context context) {
         super(context);
@@ -247,7 +247,11 @@
 
     @Override
     public void onLocationChanged(Location location) {
-        if (location != null) {
+        // Location providers may erroneously return (0.0, 0.0) when they fail to determine the
+        // device's location. These location updates can be safely ignored since the chance of a
+        // user actually being at these coordinates is quite low.
+        if (location != null
+                && !(location.getLongitude() == 0.0 && location.getLatitude() == 0.0)) {
             Slog.d(TAG, "onLocationChanged:"
                     + " provider=" + location.getProvider()
                     + " accuracy=" + location.getAccuracy()
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..71816fe 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -42,7 +42,6 @@
 import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN;
 import static com.android.server.wm.WindowManagerService.H.NOTIFY_STARTING_WINDOW_DRAWN;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
-import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
 import static com.android.server.wm.WindowManagerService.logWithStack;
 
@@ -62,12 +61,10 @@
 import android.view.IApplicationToken;
 import android.view.View;
 import android.view.WindowManager;
-import android.view.animation.Animation;
 
 import java.io.PrintWriter;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
-import java.util.function.Function;
 
 class AppTokenList extends ArrayList<AppWindowToken> {
 }
@@ -390,10 +387,10 @@
     @Override
     void removeIfPossible() {
         mIsExiting = false;
-        removeAllWindows();
+        removeAllWindowsIfPossible();
         if (mTask != null) {
             mTask.mStack.mExitingAppTokens.remove(this);
-            mTask.removeChild(this);
+            removeImmediately();
         }
     }
 
@@ -1103,6 +1100,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..cbb1843 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
@@ -302,7 +300,7 @@
         return token.asAppWindowToken();
     }
 
-    void setWindowToken(IBinder binder, WindowToken token) {
+    void addWindowToken(IBinder binder, WindowToken token) {
         final DisplayContent dc = mService.mRoot.getWindowTokenDisplay(token);
         if (dc != null) {
             // We currently don't support adding a window token to the display if the display
@@ -335,20 +333,33 @@
     WindowToken removeWindowToken(IBinder binder) {
         final WindowToken token = mTokenMap.remove(binder);
         if (token != null && token.asAppWindowToken() == null) {
+            token.setExiting();
+        }
+        return token;
+    }
+
+    /** Changes the display the input window token is housed on to this one. */
+    void reParentWindowToken(WindowToken token) {
+        final DisplayContent prevDc = token.getDisplayContent();
+        if (prevDc == this) {
+            return;
+        }
+        if (prevDc != null && prevDc.mTokenMap.remove(token.token) != null) {
             switch (token.windowType) {
                 case TYPE_WALLPAPER:
-                    mBelowAppWindowsContainers.removeChild(token);
+                    prevDc.mBelowAppWindowsContainers.removeChild(token);
                     break;
                 case TYPE_INPUT_METHOD:
                 case TYPE_INPUT_METHOD_DIALOG:
-                    mImeWindowsContainers.removeChild(token);
+                    prevDc.mImeWindowsContainers.removeChild(token);
                     break;
                 default:
-                    mAboveAppWindowsContainers.removeChild(token);
+                    prevDc.mAboveAppWindowsContainers.removeChild(token);
                     break;
             }
         }
-        return token;
+
+        addWindowToken(token.token, token);
     }
 
     void removeAppToken(IBinder binder) {
@@ -459,6 +470,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 +2594,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 +2993,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..fe0160a 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;
@@ -146,11 +146,11 @@
         if (content != null) {
             content.mDimLayerController.removeDimLayerUser(this);
         }
-        getParent().removeChild(this);
+        removeImmediately();
         mService.mTaskIdToTask.delete(mTaskId);
     }
 
-    // Change to use reparenting in WC when TaskStack is switched to use WC.
+    // Change to use re-parenting in WC when TaskStack is switched to use WC.
     void moveTaskToStack(TaskStack stack, boolean toTop) {
         if (stack == mStack) {
             return;
@@ -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 9b089ec..2b33f09 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import android.Manifest;
+import android.Manifest.permission;
 import android.animation.ValueAnimator;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -125,6 +126,7 @@
 import com.android.internal.R;
 import com.android.internal.app.IAssistScreenshotReceiver;
 import com.android.internal.os.IResultReceiver;
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.view.IInputContext;
@@ -212,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;
@@ -1412,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.
@@ -1650,7 +1654,7 @@
         if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Removing " + win + " from " + token);
         // Window will already be removed from token before this post clean-up method is called.
         if (token.isEmpty()) {
-            if (!token.explicit) {
+            if (!token.mPersistOnEmpty) {
                 token.removeImmediately();
             } else if (atoken != null) {
                 // TODO: Should this be moved into AppWindowToken.removeWindow? Might go away after
@@ -2439,8 +2443,6 @@
                     return;
                 }
 
-                token.setExiting();
-
                 mInputMonitor.updateInputWindowsLw(true /*force*/);
             }
         } finally {
@@ -2713,7 +2715,7 @@
                 return SCREEN_ORIENTATION_UNSPECIFIED;
             }
 
-            return wtoken.getOrientation();
+            return wtoken.getOrientationIgnoreVisibility();
         }
     }
 
@@ -3935,20 +3937,13 @@
     }
 
     @Override
-    public void dismissKeyguard() {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires DISABLE_KEYGUARD permission");
-        }
+    public void dismissKeyguard(IKeyguardDismissCallback callback) {
+        checkCallingPermission(permission.CONTROL_KEYGUARD, "dismissKeyguard");
         synchronized(mWindowMap) {
-            mPolicy.dismissKeyguardLw();
+            mPolicy.dismissKeyguardLw(callback);
         }
     }
 
-    @Override
-    public void keyguardGoingAway(int flags) {
-    }
-
     public void onKeyguardOccludedChanged(boolean occluded) {
         synchronized (mWindowMap) {
             mPolicy.onKeyguardOccludedChangedLw(occluded);
@@ -4093,6 +4088,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() {
@@ -6475,7 +6488,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;
                 }
 
@@ -8901,7 +8922,7 @@
                         return;
                     }
 
-                    token.removeAllWindows();
+                    token.removeAllWindowsIfPossible();
                 }
                 WindowManagerService.this.removeWindowToken(binder, displayId);
             }
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/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index a2eebc3..ebf110b 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -18,25 +18,18 @@
 
 import java.util.Comparator;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
 
-import android.os.Bundle;
 import android.os.Debug;
 import android.os.IBinder;
-import android.os.RemoteException;
 import android.util.Slog;
-import android.view.DisplayInfo;
-import android.view.animation.Animation;
 
 import java.io.PrintWriter;
 
@@ -58,8 +51,8 @@
     final int windowType;
 
     // Set if this token was explicitly added by a client, so should
-    // not be removed when all windows are removed.
-    final boolean explicit;
+    // persist (not be removed) when all windows are removed.
+    boolean mPersistOnEmpty;
 
     // For printing.
     String stringName;
@@ -104,27 +97,28 @@
         return isFirstChildWindowGreaterThanSecond(newWindow, existingWindow) ? 1 : -1;
     };
 
-    WindowToken(WindowManagerService service, IBinder _token, int type, boolean _explicit,
+    WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
             DisplayContent dc) {
         mService = service;
         token = _token;
         windowType = type;
-        explicit = _explicit;
+        mPersistOnEmpty = persistOnEmpty;
         onDisplayChanged(dc);
     }
 
-    void removeAllWindows() {
+    void removeAllWindowsIfPossible() {
         for (int i = mChildren.size() - 1; i >= 0; --i) {
             final WindowState win = mChildren.get(i);
-            if (DEBUG_WINDOW_MOVEMENT) Slog.w(TAG_WM, "removeAllWindows: removing win=" + win);
+            if (DEBUG_WINDOW_MOVEMENT) Slog.w(TAG_WM,
+                    "removeAllWindowsIfPossible: removing win=" + win);
             win.removeIfPossible();
-            if (mChildren.contains(win)) {
-                removeChild(win);
-            }
         }
     }
 
     void setExiting() {
+        // This token is exiting, so allow it to be removed when it no longer contains any windows.
+        mPersistOnEmpty = false;
+
         if (hidden) {
             return;
         }
@@ -297,16 +291,8 @@
     }
 
     void onDisplayChanged(DisplayContent dc) {
-        if (mDisplayContent == dc) {
-            return;
-        }
-
-        if (mDisplayContent != null) {
-            mDisplayContent.removeWindowToken(token);
-        }
+        dc.reParentWindowToken(this);
         mDisplayContent = dc;
-        mDisplayContent.setWindowToken(token, this);
-
         super.onDisplayChanged(dc);
     }
 
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 4d43e8e..50a6095 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -46,6 +46,7 @@
 LOCAL_SHARED_LIBRARIES += \
     libandroid_runtime \
     libandroidfw \
+    libbase \
     libappfuse \
     libbinder \
     libcutils \
@@ -72,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..7db6d42 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");
+    } else {
+        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 895497c..45f3698 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -17,10 +17,25 @@
 package com.android.server.devicepolicy;
 
 import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
+import static android.app.admin.DevicePolicyManager.CODE_ACCOUNTS_NOT_EMPTY;
+import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE;
+import static android.app.admin.DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED;
+import static android.app.admin.DevicePolicyManager.CODE_HAS_DEVICE_OWNER;
+import static android.app.admin.DevicePolicyManager.CODE_HAS_PAIRED;
+import static android.app.admin.DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED;
+import static android.app.admin.DevicePolicyManager.CODE_NONSYSTEM_USER_EXISTS;
+import static android.app.admin.DevicePolicyManager.CODE_NOT_SYSTEM_USER;
+import static android.app.admin.DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT;
+import static android.app.admin.DevicePolicyManager.CODE_OK;
+import static android.app.admin.DevicePolicyManager.CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER;
+import static android.app.admin.DevicePolicyManager.CODE_SYSTEM_USER;
+import static android.app.admin.DevicePolicyManager.CODE_USER_HAS_PROFILE_OWNER;
+import static android.app.admin.DevicePolicyManager.CODE_USER_NOT_RUNNING;
+import static android.app.admin.DevicePolicyManager.CODE_USER_SETUP_COMPLETED;
 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;
@@ -213,6 +228,8 @@
 
     private static final String TAG_ADMIN_BROADCAST_PENDING = "admin-broadcast-pending";
 
+    private static final String ATTR_ID = "id";
+
     private static final String ATTR_VALUE = "value";
 
     private static final String TAG_INITIALIZATION_BUNDLE = "initialization-bundle";
@@ -308,21 +325,6 @@
     private static final int PROFILE_KEYGUARD_FEATURES =
             PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER | PROFILE_KEYGUARD_FEATURES_PROFILE_ONLY;
 
-    private static final int CODE_OK = 0;
-    private static final int CODE_HAS_DEVICE_OWNER = 1;
-    private static final int CODE_USER_HAS_PROFILE_OWNER = 2;
-    private static final int CODE_USER_NOT_RUNNING = 3;
-    private static final int CODE_USER_SETUP_COMPLETED = 4;
-    private static final int CODE_NONSYSTEM_USER_EXISTS = 5;
-    private static final int CODE_ACCOUNTS_NOT_EMPTY = 6;
-    private static final int CODE_NOT_SYSTEM_USER = 7;
-    private static final int CODE_HAS_PAIRED = 8;
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({ CODE_OK, CODE_HAS_DEVICE_OWNER, CODE_USER_HAS_PROFILE_OWNER, CODE_USER_NOT_RUNNING,
-            CODE_USER_SETUP_COMPLETED, CODE_NOT_SYSTEM_USER })
-    private @interface DeviceOwnerPreConditionCode {}
-
     private static final int DEVICE_ADMIN_DEACTIVATE_TIMEOUT = 10000;
 
     /**
@@ -2380,7 +2382,7 @@
 
             for (String id : policy.mAffiliationIds) {
                 out.startTag(null, TAG_AFFILIATION_ID);
-                out.attribute(null, "id", id);
+                out.attribute(null, ATTR_ID, id);
                 out.endTag(null, TAG_AFFILIATION_ID);
             }
 
@@ -2560,7 +2562,7 @@
                 } else if (DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML.equals(tag)) {
                     policy.doNotAskCredentialsOnBoot = true;
                 } else if (TAG_AFFILIATION_ID.equals(tag)) {
-                    policy.mAffiliationIds.add(parser.getAttributeValue(null, "id"));
+                    policy.mAffiliationIds.add(parser.getAttributeValue(null, ATTR_ID));
                 } else if (TAG_LAST_SECURITY_LOG_RETRIEVAL.equals(tag)) {
                     policy.mLastSecurityLogRetrievalTime = Long.parseLong(
                             parser.getAttributeValue(null, ATTR_VALUE));
@@ -5977,6 +5979,12 @@
         }
     }
 
+    @Override
+    public boolean hasDeviceOwner() {
+        enforceDeviceOwnerOrManageUsers();
+        return mOwners.hasDeviceOwner();
+    }
+
     boolean isDeviceOwner(ActiveAdmin admin) {
         return isDeviceOwner(admin.info.getComponent(), admin.getUserHandle().getIdentifier());
     }
@@ -6518,7 +6526,7 @@
             enforceCanManageProfileAndDeviceOwners();
         }
 
-        final int code = checkSetDeviceOwnerPreConditionLocked(owner, userId, isAdb());
+        final int code = checkDeviceOwnerProvisioningPreConditionLocked(owner, userId, isAdb());
         switch (code) {
             case CODE_OK:
                 return;
@@ -6545,7 +6553,7 @@
                 throw new IllegalStateException("Not allowed to set the device owner because this "
                         + "device has already paired");
             default:
-                throw new IllegalStateException("Unknown @DeviceOwnerPreConditionCode " + code);
+                throw new IllegalStateException("Unexpected @ProvisioningPreCondition " + code);
         }
     }
 
@@ -7024,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);
@@ -7779,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 +
@@ -8064,13 +8073,11 @@
     public void setLockTaskPackages(ComponentName who, String[] packages)
             throws SecurityException {
         Preconditions.checkNotNull(who, "ComponentName is null");
+
         synchronized (this) {
-            ActiveAdmin deviceOwner = getActiveAdminWithPolicyForUidLocked(
-                who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER, mInjector.binderGetCallingUid());
-            ActiveAdmin profileOwner = getActiveAdminWithPolicyForUidLocked(
-                who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, mInjector.binderGetCallingUid());
-            if (deviceOwner != null || (profileOwner != null && isAffiliatedUser())) {
-                int userHandle = mInjector.userHandleGetCallingUserId();
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            final int userHandle = mInjector.userHandleGetCallingUserId();
+            if (isUserAffiliatedWithDevice(userHandle)) {
                 setLockTaskPackagesLocked(userHandle, new ArrayList<>(Arrays.asList(packages)));
             } else {
                 throw new SecurityException("Admin " + who +
@@ -8754,79 +8761,42 @@
 
     @Override
     public boolean isProvisioningAllowed(String action) {
+        return checkProvisioningPreConditionSkipPermission(action) == CODE_OK;
+    }
+
+    @Override
+    public int checkProvisioningPreCondition(String action) {
+        enforceCanManageProfileAndDeviceOwners();
+        return checkProvisioningPreConditionSkipPermission(action);
+    }
+
+    private int checkProvisioningPreConditionSkipPermission(String action) {
         if (!mHasFeature) {
-            return false;
+            return CODE_DEVICE_ADMIN_NOT_SUPPORTED;
         }
 
         final int callingUserId = mInjector.userHandleGetCallingUserId();
-        if (DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE.equals(action)) {
-            if (!hasFeatureManagedUsers()) {
-                return false;
+        if (action != null) {
+            switch (action) {
+                case DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE:
+                    return checkManagedProfileProvisioningPreCondition(callingUserId);
+                case DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE:
+                    return checkDeviceOwnerProvisioningPreCondition(callingUserId);
+                case DevicePolicyManager.ACTION_PROVISION_MANAGED_USER:
+                    return checkManagedUserProvisioningPreCondition(callingUserId);
+                case DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE:
+                    return checkManagedShareableDeviceProvisioningPreCondition(callingUserId);
             }
-            synchronized (this) {
-                if (mOwners.hasDeviceOwner()) {
-                    // STOPSHIP Only allow creating a managed profile if allowed by the device
-                    // owner. http://b/31952368
-                    if (mInjector.userManagerIsSplitSystemUser()) {
-                        if (callingUserId == UserHandle.USER_SYSTEM) {
-                            // Managed-profiles cannot be setup on the system user.
-                            return false;
-                        }
-                    }
-                }
-            }
-            if (getProfileOwner(callingUserId) != null) {
-                // Managed user cannot have a managed profile.
-                return false;
-            }
-            boolean canRemoveProfile
-                    = !mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER);
-            final long ident = mInjector.binderClearCallingIdentity();
-            try {
-                if (!mUserManager.canAddMoreManagedProfiles(callingUserId, canRemoveProfile)) {
-                    return false;
-                }
-            } finally {
-                mInjector.binderRestoreCallingIdentity(ident);
-            }
-            return true;
-        } else if (DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE.equals(action)) {
-            return isDeviceOwnerProvisioningAllowed(callingUserId);
-        } else if (DevicePolicyManager.ACTION_PROVISION_MANAGED_USER.equals(action)) {
-            if (!hasFeatureManagedUsers()) {
-                return false;
-            }
-            if (!mInjector.userManagerIsSplitSystemUser()) {
-                // ACTION_PROVISION_MANAGED_USER only supported on split-user systems.
-                return false;
-            }
-            if (callingUserId == UserHandle.USER_SYSTEM) {
-                // System user cannot be a managed user.
-                return false;
-            }
-            if (hasUserSetupCompleted(callingUserId)) {
-                return false;
-            }
-            if (mIsWatch && hasPaired(UserHandle.USER_SYSTEM)) {
-                return false;
-            }
-            return true;
-        } else if (DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE.equals(action)) {
-            if (!mInjector.userManagerIsSplitSystemUser()) {
-                // ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE only supported on split-user systems.
-                return false;
-            }
-            return isDeviceOwnerProvisioningAllowed(callingUserId);
         }
         throw new IllegalArgumentException("Unknown provisioning action " + action);
     }
 
-    /*
+    /**
      * The device owner can only be set before the setup phase of the primary user has completed,
      * except for adb command if no accounts or additional users are present on the device.
      */
-    private synchronized @DeviceOwnerPreConditionCode int checkSetDeviceOwnerPreConditionLocked(
-            @Nullable ComponentName owner, int deviceOwnerUserId, boolean isAdb) {
+    private int checkDeviceOwnerProvisioningPreConditionLocked(@Nullable ComponentName owner,
+            int deviceOwnerUserId, boolean isAdb) {
         if (mOwners.hasDeviceOwner()) {
             return CODE_HAS_DEVICE_OWNER;
         }
@@ -8871,13 +8841,75 @@
         }
     }
 
-    private boolean isDeviceOwnerProvisioningAllowed(int deviceOwnerUserId) {
+    private int checkDeviceOwnerProvisioningPreCondition(int deviceOwnerUserId) {
         synchronized (this) {
-            return CODE_OK == checkSetDeviceOwnerPreConditionLocked(
-                    /* owner unknown */ null, deviceOwnerUserId, /* isAdb */ false);
+            return checkDeviceOwnerProvisioningPreConditionLocked(/* owner unknown */ null,
+                    deviceOwnerUserId, /* isAdb= */ false);
         }
     }
 
+    private int checkManagedProfileProvisioningPreCondition(int callingUserId) {
+        if (!hasFeatureManagedUsers()) {
+            return CODE_MANAGED_USERS_NOT_SUPPORTED;
+        }
+        synchronized (this) {
+            if (mOwners.hasDeviceOwner()) {
+                // STOPSHIP Only allow creating a managed profile if allowed by the device
+                // owner. http://b/31952368
+                if (mInjector.userManagerIsSplitSystemUser()) {
+                    if (callingUserId == UserHandle.USER_SYSTEM) {
+                        // Managed-profiles cannot be setup on the system user.
+                        return CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER;
+                    }
+                }
+            }
+        }
+        if (getProfileOwner(callingUserId) != null) {
+            // Managed user cannot have a managed profile.
+            return CODE_USER_HAS_PROFILE_OWNER;
+        }
+        boolean canRemoveProfile =
+                !mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER);
+        final long ident = mInjector.binderClearCallingIdentity();
+        try {
+            if (!mUserManager.canAddMoreManagedProfiles(callingUserId, canRemoveProfile)) {
+                return CODE_CANNOT_ADD_MANAGED_PROFILE;
+            }
+        } finally {
+            mInjector.binderRestoreCallingIdentity(ident);
+        }
+        return CODE_OK;
+    }
+
+    private int checkManagedUserProvisioningPreCondition(int callingUserId) {
+        if (!hasFeatureManagedUsers()) {
+            return CODE_MANAGED_USERS_NOT_SUPPORTED;
+        }
+        if (!mInjector.userManagerIsSplitSystemUser()) {
+            // ACTION_PROVISION_MANAGED_USER only supported on split-user systems.
+            return CODE_NOT_SYSTEM_USER_SPLIT;
+        }
+        if (callingUserId == UserHandle.USER_SYSTEM) {
+            // System user cannot be a managed user.
+            return CODE_SYSTEM_USER;
+        }
+        if (hasUserSetupCompleted(callingUserId)) {
+            return CODE_USER_SETUP_COMPLETED;
+        }
+        if (mIsWatch && hasPaired(UserHandle.USER_SYSTEM)) {
+            return CODE_HAS_PAIRED;
+        }
+        return CODE_OK;
+    }
+
+    private int checkManagedShareableDeviceProvisioningPreCondition(int callingUserId) {
+        if (!mInjector.userManagerIsSplitSystemUser()) {
+            // ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE only supported on split-user systems.
+            return CODE_NOT_SYSTEM_USER_SPLIT;
+        }
+        return checkDeviceOwnerProvisioningPreCondition(callingUserId);
+    }
+
     private boolean hasFeatureManagedUsers() {
         try {
             return mIPackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0);
@@ -9120,7 +9152,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 +9179,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;
@@ -9163,9 +9207,18 @@
 
     @Override
     public void setAffiliationIds(ComponentName admin, List<String> ids) {
-        final Set<String> affiliationIds = new ArraySet<String>(ids);
-        final int callingUserId = mInjector.userHandleGetCallingUserId();
+        if (!mHasFeature) {
+            return;
+        }
 
+        Preconditions.checkNotNull(admin);
+        Preconditions.checkCollectionElementsNotNull(ids, "ids");
+
+        final Set<String> affiliationIds = new ArraySet<String>(ids);
+        Preconditions.checkArgument(
+                !affiliationIds.contains(""), "ids must not contain empty strings");
+
+        final int callingUserId = mInjector.userHandleGetCallingUserId();
         synchronized (this) {
             getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             getUserData(callingUserId).mAffiliationIds = affiliationIds;
@@ -9180,20 +9233,44 @@
     }
 
     @Override
-    public boolean isAffiliatedUser() {
-        final int callingUserId = mInjector.userHandleGetCallingUserId();
+    public List<String> getAffiliationIds(ComponentName admin) {
+        if (!mHasFeature) {
+            return Collections.emptyList();
+        }
 
+        Preconditions.checkNotNull(admin);
         synchronized (this) {
-            if (mOwners.getDeviceOwnerUserId() == callingUserId) {
-                // The user that the DO is installed on is always affiliated.
-                return true;
-            }
-            final ComponentName profileOwner = getProfileOwner(callingUserId);
-            if (profileOwner == null
-                    || !profileOwner.getPackageName().equals(mOwners.getDeviceOwnerPackageName())) {
+            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            return new ArrayList<String>(
+                    getUserData(mInjector.userHandleGetCallingUserId()).mAffiliationIds);
+        }
+    }
+
+    @Override
+    public boolean isAffiliatedUser() {
+        return isUserAffiliatedWithDevice(mInjector.userHandleGetCallingUserId());
+    }
+
+    private boolean isUserAffiliatedWithDevice(int userId) {
+        synchronized (this) {
+            if (!mOwners.hasDeviceOwner()) {
                 return false;
             }
-            final Set<String> userAffiliationIds = getUserData(callingUserId).mAffiliationIds;
+            if (userId == mOwners.getDeviceOwnerUserId()) {
+                // The user that the DO is installed on is always affiliated with the device.
+                return true;
+            }
+            if (userId == UserHandle.USER_SYSTEM) {
+                // The system user is always affiliated in a DO device, even if the DO is set on a
+                // different user. This could be the case if the DO is set in the primary user
+                // of a split user device.
+                return true;
+            }
+            final ComponentName profileOwner = getProfileOwner(userId);
+            if (profileOwner == null) {
+                return false;
+            }
+            final Set<String> userAffiliationIds = getUserData(userId).mAffiliationIds;
             final Set<String> deviceAffiliationIds =
                     getUserData(UserHandle.USER_SYSTEM).mAffiliationIds;
             for (String id : userAffiliationIds) {
@@ -9557,6 +9634,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");
@@ -9577,9 +9658,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(
@@ -9621,8 +9701,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;
                     }
@@ -9835,35 +9914,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/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 3114f3f..ab38e43 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -49,6 +49,7 @@
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Matchers.isA;
+import static org.mockito.Matchers.isNull;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
@@ -141,6 +142,15 @@
 
 /**
  * Tests for {@link NetworkPolicyManagerService}.
+ *
+ * <p>Typical usage:
+ *
+ * <pre><code>
+    m -j32 FrameworksServicesTests && adb install -r -g \
+    ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk && \
+    adb shell am instrument -e class "com.android.server.NetworkPolicyManagerServiceTest" -w \
+    "com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner"
+ * </code></pre>
  */
 @RunWith(AndroidJUnit4.class)
 @MediumTest
@@ -247,7 +257,7 @@
                 return null;
             }
         }).when(mActivityManager).registerUidObserver(any(), anyInt(),
-                ActivityManager.PROCESS_STATE_UNKNOWN, null);
+                eq(ActivityManager.PROCESS_STATE_UNKNOWN), isNull(String.class));
 
         mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, mStatsService,
                 mNetworkManager, mIpm, mTime, mPolicyDir, true);
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 cff5b41..0c00886 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;
@@ -50,6 +55,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -1643,6 +1649,7 @@
     /**
      * Test for:
      * {@link DevicePolicyManager#setAffiliationIds}
+     * {@link DevicePolicyManager#getAffiliationIds}
      * {@link DevicePolicyManager#isAffiliatedUser}
      */
     public void testUserAffiliation() throws Exception {
@@ -1659,30 +1666,34 @@
         dpm.setActiveAdmin(admin1, /* replace =*/ false);
         assertTrue(dpm.setDeviceOwner(admin1, "owner-name"));
         assertTrue(dpm.isAffiliatedUser());
+        assertTrue(dpm.getAffiliationIds(admin1).isEmpty());
 
-        // Install a profile owner whose package name matches the device owner on a test user. Check
-        // that the test user is unaffiliated.
+        // Install a profile owner. Check that the test user is unaffiliated.
         mContext.binder.callingUid = DpmMockContext.CALLER_UID;
         setAsProfileOwner(admin2);
         assertFalse(dpm.isAffiliatedUser());
+        assertTrue(dpm.getAffiliationIds(admin2).isEmpty());
 
         // Have the profile owner specify a set of affiliation ids. Check that the test user remains
         // unaffiliated.
-        final Set<String> userAffiliationIds = new ArraySet<>();
+        final List<String> userAffiliationIds = new ArrayList<>();
         userAffiliationIds.add("red");
         userAffiliationIds.add("green");
         userAffiliationIds.add("blue");
         dpm.setAffiliationIds(admin2, userAffiliationIds);
+        MoreAsserts.assertContentsInAnyOrder(dpm.getAffiliationIds(admin2), "red", "green", "blue");
         assertFalse(dpm.isAffiliatedUser());
 
         // Have the device owner specify a set of affiliation ids that do not intersect with those
         // specified by the profile owner. Check that the test user remains unaffiliated.
-        final Set<String> deviceAffiliationIds = new ArraySet<>();
+        final List<String> deviceAffiliationIds = new ArrayList<>();
         deviceAffiliationIds.add("cyan");
         deviceAffiliationIds.add("yellow");
         deviceAffiliationIds.add("magenta");
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         dpm.setAffiliationIds(admin1, deviceAffiliationIds);
+        MoreAsserts.assertContentsInAnyOrder(
+            dpm.getAffiliationIds(admin1), "cyan", "yellow", "magenta");
         mContext.binder.callingUid = DpmMockContext.CALLER_UID;
         assertFalse(dpm.isAffiliatedUser());
 
@@ -1690,19 +1701,13 @@
         // specified by the device owner. Check that the test user becomes affiliated.
         userAffiliationIds.add("yellow");
         dpm.setAffiliationIds(admin2, userAffiliationIds);
+        MoreAsserts.assertContentsInAnyOrder(
+            dpm.getAffiliationIds(admin2), "red", "green", "blue", "yellow");
         assertTrue(dpm.isAffiliatedUser());
 
-        // Change the profile owner to one whose package name does not match the device owner. Check
-        // that the test user is not affiliated anymore.
-        dpm.clearProfileOwner(admin2);
-        final ComponentName admin = new ComponentName("test", "test");
-
-        setUpPackageManagerForFakeAdmin(admin, DpmMockContext.CALLER_UID,
-                /* enabledSetting =*/ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
-                /* appTargetSdk = */ null, admin2);
-
-        dpm.setActiveAdmin(admin, /* refreshing =*/ true, DpmMockContext.CALLER_USER_HANDLE);
-        assertTrue(dpm.setProfileOwner(admin, "owner-name", DpmMockContext.CALLER_USER_HANDLE));
+        // Clear affiliation ids for the profile owner. The user becomes unaffiliated.
+        dpm.setAffiliationIds(admin2, Collections.emptyList());
+        assertTrue(dpm.getAffiliationIds(admin2).isEmpty());
         assertFalse(dpm.isAffiliatedUser());
 
         // Check that the system user remains affiliated.
@@ -1988,7 +1993,7 @@
         // UnfinishedVerificationException.
     }
 
-    public void testIsProvisioningAllowed_DeviceAdminFeatureOff() throws Exception {
+    public void setup_DeviceAdminFeatureOff() throws Exception {
         when(mContext.packageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN))
                 .thenReturn(false);
         when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
@@ -2000,7 +2005,10 @@
         setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+    }
 
+    public void testIsProvisioningAllowed_DeviceAdminFeatureOff() throws Exception {
+        setup_DeviceAdminFeatureOff();
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, false);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
@@ -2008,7 +2016,21 @@
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false);
     }
 
-    public void testIsProvisioningAllowed_ManagedProfileFeatureOff() throws Exception {
+    public void testCheckProvisioningPreCondition_DeviceAdminFeatureOff() throws Exception {
+        setup_DeviceAdminFeatureOff();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED);
+        assertCheckProvisioningPreCondition(
+                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED);
+    }
+
+    public void setup_ManagedProfileFeatureOff() throws Exception {
         when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
                 .thenReturn(false);
         initializeDpms();
@@ -2018,7 +2040,10 @@
         setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+    }
 
+    public void testIsProvisioningAllowed_ManagedProfileFeatureOff() throws Exception {
+        setup_ManagedProfileFeatureOff();
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
@@ -2034,7 +2059,33 @@
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false);
     }
 
-    public void testIsProvisioningAllowed_nonSplitUser_firstBoot_primaryUser() throws Exception {
+    public void testCheckProvisioningPreCondition_ManagedProfileFeatureOff() throws Exception {
+        setup_ManagedProfileFeatureOff();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED);
+        assertCheckProvisioningPreCondition(
+                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED);
+
+        // Test again when split user is on
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED);
+        assertCheckProvisioningPreCondition(
+                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED);
+    }
+
+    public void setup_nonSplitUser_firstBoot_primaryUser() throws Exception {
         when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
                 .thenReturn(true);
         when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
@@ -2043,7 +2094,10 @@
         setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+    }
 
+    public void testIsProvisioningAllowed_nonSplitUser_firstBoot_primaryUser() throws Exception {
+        setup_nonSplitUser_firstBoot_primaryUser();
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
@@ -2052,8 +2106,22 @@
                 false /* because of non-split user */);
     }
 
-    public void testIsProvisioningAllowed_nonSplitUser_afterDeviceSetup_primaryUser()
+    public void testCheckProvisioningPreCondition_nonSplitUser_firstBoot_primaryUser()
             throws Exception {
+        setup_nonSplitUser_firstBoot_primaryUser();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(
+                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT);
+    }
+
+    public void setup_nonSplitUser_afterDeviceSetup_primaryUser() throws Exception {
         when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
                 .thenReturn(true);
         when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
@@ -2062,7 +2130,11 @@
         setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+    }
 
+    public void testIsProvisioningAllowed_nonSplitUser_afterDeviceSetup_primaryUser()
+            throws Exception {
+        setup_nonSplitUser_afterDeviceSetup_primaryUser();
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                 false/* because of completed device setup */);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
@@ -2072,7 +2144,22 @@
                 false/* because of non-split user */);
     }
 
-    public void testIsProvisioningAllowed_splitUser_firstBoot_systemUser() throws Exception {
+    public void testCheckProvisioningPreCondition_nonSplitUser_afterDeviceSetup_primaryUser()
+            throws Exception {
+        setup_nonSplitUser_afterDeviceSetup_primaryUser();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                DevicePolicyManager.CODE_USER_SETUP_COMPLETED);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(
+                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT);
+    }
+
+    public void setup_splitUser_firstBoot_systemUser() throws Exception {
         when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
                 .thenReturn(true);
         when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
@@ -2081,7 +2168,10 @@
         setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+    }
 
+    public void testIsProvisioningAllowed_splitUser_firstBoot_systemUser() throws Exception {
+        setup_splitUser_firstBoot_systemUser();
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                 false /* because canAddMoreManagedProfiles returns false */);
@@ -2089,10 +2179,24 @@
                 true);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
                 false/* because calling uid is system user */);
-
     }
 
-    public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_systemUser() throws Exception {
+    public void testCheckProvisioningPreCondition_splitUser_firstBoot_systemUser()
+            throws Exception {
+        setup_splitUser_firstBoot_systemUser();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE);
+        assertCheckProvisioningPreCondition(
+                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                DevicePolicyManager.CODE_SYSTEM_USER);
+    }
+
+    public void setup_splitUser_afterDeviceSetup_systemUser() throws Exception {
         when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
                 .thenReturn(true);
         when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
@@ -2101,7 +2205,10 @@
         setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+    }
 
+    public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_systemUser() throws Exception {
+        setup_splitUser_afterDeviceSetup_systemUser();
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                 true/* it's undefined behavior. Can be changed into false in the future */);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
@@ -2112,7 +2219,22 @@
                 false/* because calling uid is system user */);
     }
 
-    public void testIsProvisioningAllowed_splitUser_firstBoot_primaryUser() throws Exception {
+    public void testCheckProvisioningPreCondition_splitUser_afterDeviceSetup_systemUser()
+            throws Exception {
+        setup_splitUser_afterDeviceSetup_systemUser();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE);
+        assertCheckProvisioningPreCondition(
+                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                DevicePolicyManager.CODE_SYSTEM_USER);
+    }
+
+    public void setup_splitUser_firstBoot_primaryUser() throws Exception {
         when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
                 .thenReturn(true);
         when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
@@ -2121,17 +2243,33 @@
         setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+    }
 
+    public void testIsProvisioningAllowed_splitUser_firstBoot_primaryUser() throws Exception {
+        setup_splitUser_firstBoot_primaryUser();
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
                 true);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, true);
-
     }
 
-    public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_primaryUser()
+    public void testCheckProvisioningPreCondition_splitUser_firstBoot_primaryUser()
             throws Exception {
+        setup_splitUser_firstBoot_primaryUser();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(
+                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                DevicePolicyManager.CODE_OK);
+    }
+
+    public void setup_splitUser_afterDeviceSetup_primaryUser() throws Exception {
         when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
                 .thenReturn(true);
         when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
@@ -2140,7 +2278,11 @@
         setUserSetupCompleteForUser(true, DpmMockContext.CALLER_USER_HANDLE);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+    }
 
+    public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_primaryUser()
+            throws Exception {
+        setup_splitUser_afterDeviceSetup_primaryUser();
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                 true/* it's undefined behavior. Can be changed into false in the future */);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
@@ -2150,8 +2292,22 @@
                 false/* because user setup completed */);
     }
 
-    public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_systemUser()
+    public void testCheckProvisioningPreCondition_splitUser_afterDeviceSetup_primaryUser()
             throws Exception {
+        setup_splitUser_afterDeviceSetup_primaryUser();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(
+                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                DevicePolicyManager.CODE_USER_SETUP_COMPLETED);
+    }
+
+    public void setup_provisionManagedProfileWithDeviceOwner_systemUser() throws Exception {
         setDeviceOwner();
 
         when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
@@ -2162,13 +2318,24 @@
         setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+    }
 
+    public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_systemUser()
+            throws Exception {
+        setup_provisionManagedProfileWithDeviceOwner_systemUser();
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                 false /* can't provision managed profile on system user */);
     }
 
-    public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_primaryUser()
+    public void testCheckProvisioningPreCondition_provisionManagedProfileWithDeviceOwner_systemUser()
             throws Exception {
+        setup_provisionManagedProfileWithDeviceOwner_systemUser();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER);
+    }
+
+    private void setup_provisionManagedProfileWithDeviceOwner_primaryUser() throws Exception {
         setDeviceOwner();
 
         when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
@@ -2179,12 +2346,23 @@
         setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+    }
 
+    public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_primaryUser()
+            throws Exception {
+        setup_provisionManagedProfileWithDeviceOwner_primaryUser();
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
     }
 
-    public void testIsProvisioningAllowed_provisionManagedProfileCantRemoveUser_primaryUser()
+    public void testCheckProvisioningPreCondition_provisionManagedProfileWithDeviceOwner_primaryUser()
             throws Exception {
+        setup_provisionManagedProfileWithDeviceOwner_primaryUser();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_OK);
+    }
+
+    private void setup_provisionManagedProfileCantRemoveUser_primaryUser() throws Exception {
         setDeviceOwner();
 
         when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
@@ -2193,16 +2371,37 @@
         when(mContext.userManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER))
                 .thenReturn(true);
         when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
-                false /* we can't remove a managed profile*/)).thenReturn(false);
+                false /* we can't remove a managed profile */)).thenReturn(false);
         when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
                 true)).thenReturn(true);
         setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+    }
 
+    public void testIsProvisioningAllowed_provisionManagedProfileCantRemoveUser_primaryUser()
+            throws Exception {
+        setup_provisionManagedProfileCantRemoveUser_primaryUser();
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
     }
 
+    public void testCheckProvisioningPreCondition_provisionManagedProfileCantRemoveUser_primaryUser()
+            throws Exception {
+        setup_provisionManagedProfileCantRemoveUser_primaryUser();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE);
+    }
+
+    public void testCheckProvisioningPreCondition_permission() {
+        // GIVEN the permission MANAGE_PROFILE_AND_DEVICE_OWNERS is not granted
+        try {
+            dpm.checkProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE);
+            fail("Didn't throw SecurityException");
+        } catch (SecurityException expected) {
+        }
+    }
+
     public void testForceUpdateUserSetupComplete_permission() {
         // GIVEN the permission MANAGE_PROFILE_AND_DEVICE_OWNERS is not granted
         try {
@@ -2447,6 +2646,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 +2761,27 @@
         assertEquals("isProvisioningAllowed(" + action + ") returning unexpected result", expected,
                 dpm.isProvisioningAllowed(action));
     }
+
+    private void assertCheckProvisioningPreCondition(String action, int provisioningCondition) {
+        assertEquals("checkProvisioningPreCondition(" + action + ") returning unexpected result",
+                provisioningCondition, dpm.checkProvisioningPreCondition(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/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
new file mode 100644
index 0000000..84bb4e8
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.pm;
+
+import android.content.pm.PackageParser;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+
+import static org.junit.Assert.*;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import libcore.io.IoUtils;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class PackageParserTest {
+    private File mTmpDir;
+    private static final File FRAMEWORK = new File("/system/framework/framework-res.apk");
+
+    @Before
+    public void setUp() {
+        // Create a new temporary directory for each of our tests.
+        mTmpDir = IoUtils.createTemporaryDirectory("PackageParserTest");
+    }
+
+    @Test
+    public void testParse_noCache() throws Exception {
+        PackageParser pp = new CachePackageNameParser();
+        PackageParser.Package pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
+                false /* useCaches */);
+        assertNotNull(pkg);
+
+        pp.setCacheDir(mTmpDir);
+        pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
+                false /* useCaches */);
+        assertNotNull(pkg);
+
+        // Make sure that we always write out a cache entry for future reference,
+        // whether or not we're asked to use caches.
+        assertEquals(1, mTmpDir.list().length);
+    }
+
+    @Test
+    public void testParse_withCache() throws Exception {
+        PackageParser pp = new CachePackageNameParser();
+
+        pp.setCacheDir(mTmpDir);
+        // The first parse will write this package to the cache.
+        pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
+
+        // Now attempt to parse the package again, should return the
+        // cached result.
+        PackageParser.Package pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
+                true /* useCaches */);
+        assertEquals("cache_android", pkg.packageName);
+
+        // Try again, with useCaches == false, shouldn't return the parsed
+        // result.
+        pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */);
+        assertEquals("android", pkg.packageName);
+
+        // We haven't set a cache directory here : the parse should still succeed,
+        // just not using the cached results.
+        pp = new CachePackageNameParser();
+        pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
+        assertEquals("android", pkg.packageName);
+
+        pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */);
+        assertEquals("android", pkg.packageName);
+    }
+
+    /**
+     * A trivial subclass of package parser that only caches the package name, and throws away
+     * all other information.
+     */
+    public static class CachePackageNameParser extends PackageParser {
+        @Override
+        public byte[] toCacheEntry(Package pkg) {
+            return ("cache_" + pkg.packageName).getBytes(StandardCharsets.UTF_8);
+        }
+
+        @Override
+        public Package fromCacheEntry(byte[] cacheEntry) {
+            return new Package(new String(cacheEntry, StandardCharsets.UTF_8));
+        }
+    }
+}
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/twilight/TwilightServiceTest.java b/services/tests/servicestests/src/com/android/server/twilight/TwilightServiceTest.java
new file mode 100644
index 0000000..751e4b5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/twilight/TwilightServiceTest.java
@@ -0,0 +1,71 @@
+package com.android.server.twilight;
+
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.app.AlarmManager;
+import android.content.Context;
+import android.location.Location;
+import android.test.AndroidTestCase;
+
+public class TwilightServiceTest extends AndroidTestCase {
+
+    private TwilightService mTwilightService;
+    private Location mInitialLocation;
+
+    @Override
+    protected void setUp() throws Exception {
+        final Context context = getContext();
+        mTwilightService = new TwilightService(context);
+        mTwilightService.mAlarmManager =
+                (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+
+        mInitialLocation = createMockLocation(10.0, 10.0);
+        mTwilightService.onLocationChanged(mInitialLocation);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mTwilightService = null;
+        mInitialLocation = null;
+    }
+
+    public void testValidLocation_updatedLocation() {
+        final TwilightState priorState = mTwilightService.mLastTwilightState;
+        final Location validLocation = createMockLocation(35.0, 35.0);
+        mTwilightService.onLocationChanged(validLocation);
+        assertEquals(mTwilightService.mLastLocation, validLocation);
+        assertNotSame(priorState, mTwilightService.mLastTwilightState);
+    }
+
+    public void testInvalidLocation_ignoreLocationUpdate() {
+        final TwilightState priorState = mTwilightService.mLastTwilightState;
+        final Location invalidLocation = createMockLocation(0.0, 0.0);
+        mTwilightService.onLocationChanged(invalidLocation);
+        assertEquals(mTwilightService.mLastLocation, mInitialLocation);
+        assertEquals(priorState, mTwilightService.mLastTwilightState);
+    }
+
+    private Location createMockLocation(double latitude, double longitude) {
+        // There's no empty constructor, so we initialize with a string and quickly reset it.
+        final Location location = new Location("");
+        location.reset();
+        location.setLatitude(latitude);
+        location.setLongitude(longitude);
+        return location;
+    }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index 207939f..06837d3 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -16,17 +16,12 @@
 
 package com.android.server.wm;
 
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import android.content.Context;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.view.IWindow;
-import android.view.WindowManager;
 
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -49,7 +44,7 @@
 
     @Test
     public void testAddWindow_Order() throws Exception {
-        final TestAppWindowToken token = new TestAppWindowToken();
+        final TestAppWindowToken token = new TestAppWindowToken(sDisplayContent);
 
         assertEquals(0, token.getWindowsCount());
 
@@ -59,11 +54,6 @@
         final WindowState baseWin = createWindow(null, TYPE_BASE_APPLICATION, token, "baseWin");
         final WindowState win4 = createWindow(null, TYPE_APPLICATION, token, "win4");
 
-        token.addWindow(win1);
-        token.addWindow(startingWin);
-        token.addWindow(baseWin);
-        token.addWindow(win4);
-
         // Should not contain the windows that were added above.
         assertEquals(4, token.getWindowsCount());
         assertTrue(token.hasWindow(win1));
@@ -80,43 +70,17 @@
 
     @Test
     public void testFindMainWindow() throws Exception {
-        final TestAppWindowToken token = new TestAppWindowToken();
+        final TestAppWindowToken token = new TestAppWindowToken(sDisplayContent);
 
         assertNull(token.findMainWindow());
 
         final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, token, "window1");
         final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token, "window11");
         final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token, "window12");
-        token.addWindow(window1);
         assertEquals(window1, token.findMainWindow());
         window1.mAnimatingExit = true;
         assertEquals(window1, token.findMainWindow());
         final WindowState window2 = createWindow(null, TYPE_APPLICATION_STARTING, token, "window2");
-        token.addWindow(window2);
         assertEquals(window2, token.findMainWindow());
     }
-
-    /* Used so we can gain access to some protected members of the {@link AppWindowToken} class */
-    private class TestAppWindowToken extends AppWindowToken {
-
-        TestAppWindowToken() {
-            super(sWm, null, false, sWm.getDefaultDisplayContentLocked());
-        }
-
-        int getWindowsCount() {
-            return mChildren.size();
-        }
-
-        boolean hasWindow(WindowState w) {
-            return mChildren.contains(w);
-        }
-
-        WindowState getFirstChild() {
-            return mChildren.getFirst();
-        }
-
-        WindowState getLastChild() {
-            return mChildren.getLast();
-        }
-    }
 }
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/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index ed4c79f..1853a65 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -16,9 +16,11 @@
 
 package com.android.server.wm;
 
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
 import com.android.server.input.InputManagerService;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
@@ -528,8 +530,7 @@
     }
 
     @Override
-    public void dismissKeyguardLw() {
-
+    public void dismissKeyguardLw(@Nullable IKeyguardDismissCallback callback) {
     }
 
     @Override
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..3a69537 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. */
@@ -56,9 +98,9 @@
         Assert.assertTrue("Excepted " + first + " to be greater than " + second, first > second);
     }
 
-    WindowToken createWindowToken(DisplayContent dc, int type) {
+    private WindowToken createWindowToken(DisplayContent dc, int type) {
         if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
-            return new WindowToken(sWm, mock(IBinder.class), type, false, dc);
+            return new TestWindowToken(type, dc);
         }
 
         final int stackId = sNextStackId++;
@@ -66,7 +108,7 @@
         final TaskStack stack = sWm.mStackIdToStack.get(stackId);
         final Task task = new Task(sNextTaskId++, stack, 0, sWm, null, EMPTY, false);
         stack.addTask(task, true);
-        final AppWindowToken token = new AppWindowToken(sWm, null, false, dc);
+        final TestAppWindowToken token = new TestAppWindowToken(dc);
         task.addAppToken(0, token, 0, false);
         return token;
     }
@@ -87,4 +129,48 @@
         token.addWindow(w);
         return w;
     }
+
+    /* Used so we can gain access to some protected members of the {@link WindowToken} class */
+    class TestWindowToken extends WindowToken {
+
+        TestWindowToken(int type, DisplayContent dc) {
+            this(type, dc, false /* persistOnEmpty */);
+        }
+
+        TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty) {
+            super(sWm, mock(IBinder.class), type, persistOnEmpty, dc);
+        }
+
+        int getWindowsCount() {
+            return mChildren.size();
+        }
+
+        boolean hasWindow(WindowState w) {
+            return mChildren.contains(w);
+        }
+    }
+
+    /* Used so we can gain access to some protected members of the {@link AppWindowToken} class */
+    class TestAppWindowToken extends AppWindowToken {
+
+        TestAppWindowToken(DisplayContent dc) {
+            super(sWm, null, false, dc);
+        }
+
+        int getWindowsCount() {
+            return mChildren.size();
+        }
+
+        boolean hasWindow(WindowState w) {
+            return mChildren.contains(w);
+        }
+
+        WindowState getFirstChild() {
+            return mChildren.getFirst();
+        }
+
+        WindowState getLastChild() {
+            return mChildren.getLast();
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
index d6bfa17..0c053b9 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
@@ -16,24 +16,19 @@
 
 package com.android.server.wm;
 
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import android.content.Context;
-import android.os.IBinder;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.view.IWindow;
-import android.view.WindowManager;
 
-import static android.app.AppOpsManager.OP_NONE;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
@@ -51,7 +46,7 @@
 
     @Test
     public void testAddWindow() throws Exception {
-        final TestWindowToken token = new TestWindowToken();
+        final TestWindowToken token = new TestWindowToken(0, sDisplayContent);
 
         assertEquals(0, token.getWindowsCount());
 
@@ -80,15 +75,13 @@
 
     @Test
     public void testChildRemoval() throws Exception {
-        final TestWindowToken token = new TestWindowToken();
-        final DisplayContent dc = sWm.getDefaultDisplayContentLocked();
+        final DisplayContent dc = sDisplayContent;
+        final TestWindowToken token = new TestWindowToken(0, dc);
 
         assertEquals(token, dc.getWindowToken(token.token));
 
         final WindowState window1 = createWindow(null, TYPE_APPLICATION, token, "window1");
         final WindowState window2 = createWindow(null, TYPE_APPLICATION, token, "window2");
-        token.addWindow(window1);
-        token.addWindow(window2);
 
         window2.removeImmediately();
         // The token should still be mapped in the display content since it still has a child.
@@ -102,17 +95,13 @@
 
     @Test
     public void testAdjustAnimLayer() throws Exception {
-        final TestWindowToken token = new TestWindowToken();
+        final TestWindowToken token = new TestWindowToken(0, sDisplayContent);
         final WindowState window1 = createWindow(null, TYPE_APPLICATION, token, "window1");
         final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token, "window11");
         final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token, "window12");
         final WindowState window2 = createWindow(null, TYPE_APPLICATION, token, "window2");
         final WindowState window3 = createWindow(null, TYPE_APPLICATION, token, "window3");
 
-        token.addWindow(window1);
-        token.addWindow(window2);
-        token.addWindow(window3);
-
         final int adj = 50;
         final int window2StartLayer = window2.mLayer = 100;
         final int window3StartLayer = window3.mLayer = 200;
@@ -126,19 +115,39 @@
         assertEquals(window3StartLayer + adj, highestLayer);
     }
 
-    /* Used so we can gain access to some protected members of the {@link WindowToken} class */
-    private class TestWindowToken extends WindowToken {
+    /**
+     * Test that a window token isn't orphaned by the system when it is requested to be removed.
+     * Tokens should only be removed from the system when all their windows are gone.
+     */
+    @Test
+    public void testTokenRemovalProcess() throws Exception {
+        final TestWindowToken token =
+                new TestWindowToken(TYPE_TOAST, sDisplayContent, true /* persistOnEmpty */);
 
-        TestWindowToken() {
-            super(sWm, mock(IBinder.class), 0, false, sWm.getDefaultDisplayContentLocked());
-        }
+        // Verify that the token is on the display
+        assertNotNull(sDisplayContent.getWindowToken(token.token));
 
-        int getWindowsCount() {
-            return mChildren.size();
-        }
+        final WindowState window1 = createWindow(null, TYPE_TOAST, token, "window1");
+        final WindowState window2 = createWindow(null, TYPE_TOAST, token, "window2");
 
-        boolean hasWindow(WindowState w) {
-            return mChildren.contains(w);
-        }
+        sDisplayContent.removeWindowToken(token.token);
+        // Verify that the token is no longer mapped on the display
+        assertNull(sDisplayContent.getWindowToken(token.token));
+        // Verify that the token is still attached to its parent
+        assertNotNull(token.getParent());
+        // Verify that the token windows are still around.
+        assertEquals(2, token.getWindowsCount());
+
+        window1.removeImmediately();
+        // Verify that the token is still attached to its parent
+        assertNotNull(token.getParent());
+        // Verify that the other token window is still around.
+        assertEquals(1, token.getWindowsCount());
+
+        window2.removeImmediately();
+        // Verify that the token is no-longer attached to its parent
+        assertNull(token.getParent());
+        // Verify that the token windows are no longer attached to it.
+        assertEquals(0, token.getWindowsCount());
     }
 }
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/aapt2/.clang-format b/tools/aapt2/.clang-format
index 545366a..71c5ef2 100644
--- a/tools/aapt2/.clang-format
+++ b/tools/aapt2/.clang-format
@@ -1,2 +1,3 @@
 BasedOnStyle: Google
+ColumnLimit: 100
 
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index a3404e5..a2b216d 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -25,7 +25,7 @@
 static const char* sMajorVersion = "2";
 
 // Update minor version whenever a feature or flag is added.
-static const char* sMinorVersion = "3";
+static const char* sMinorVersion = "4";
 
 int PrintVersion() {
   std::cerr << "Android Asset Packaging Tool (aapt) " << sMajorVersion << "."
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 36a3494..4185937 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -216,6 +216,8 @@
 
   manifest_action["supports-gl-texture"];
 
+  manifest_action["meta-data"] = meta_data_action;
+
   // Application actions.
   xml::XmlNodeAction& application_action = manifest_action["application"];
   application_action.Action(OptionalNameIsJavaClassName);
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index e9bc64a..fc6970c 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -87,6 +87,23 @@
   EXPECT_EQ(nullptr, Verify("<manifest package=\"@string/str\" />"));
 }
 
+TEST_F(ManifestFixerTest, AllowMetaData) {
+    auto doc = Verify(R"EOF(
+        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+                  package="android">
+          <meta-data />
+          <application>
+            <meta-data />
+            <activity android:name=".Hi"><meta-data /></activity>
+            <activity-alias android:name=".Ho"><meta-data /></activity-alias>
+            <receiver android:name=".OffToWork"><meta-data /></receiver>
+            <provider android:name=".We"><meta-data /></provider>
+            <service android:name=".Go"><meta-data /></service>
+          </application>
+        </manifest>)EOF");
+    ASSERT_NE(nullptr, doc);
+}
+
 TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) {
   ManifestFixerOptions options = {std::string("8"), std::string("22")};
 
diff --git a/tools/aapt2/readme.md b/tools/aapt2/readme.md
index ac411b1..8001033 100644
--- a/tools/aapt2/readme.md
+++ b/tools/aapt2/readme.md
@@ -1,5 +1,9 @@
 # Android Asset Packaging Tool 2.0 (AAPT2) release notes
 
+## Version 2.4
+### `aapt2 link ...`
+- Supports `<meta-data>` tags in `<manifest>`.
+
 ## Version 2.3
 ### `aapt2`
 - Support new `font` resource type.
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/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 4596210..a0ded87 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -20,6 +20,7 @@
 import android.graphics.Rect;
 import com.android.internal.app.IAssistScreenshotReceiver;
 import com.android.internal.os.IResultReceiver;
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
@@ -516,11 +517,7 @@
     }
 
     @Override
-    public void dismissKeyguard() {
-    }
-
-    @Override
-    public void keyguardGoingAway(int flags) throws RemoteException {
+    public void dismissKeyguard(IKeyguardDismissCallback callback) throws RemoteException {
     }
 
     @Override
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/layoutlib/bridge/tests/Android.mk b/tools/layoutlib/bridge/tests/Android.mk
index 565feb6..9ee416a 100644
--- a/tools/layoutlib/bridge/tests/Android.mk
+++ b/tools/layoutlib/bridge/tests/Android.mk
@@ -30,7 +30,7 @@
 			layoutlib_api-prebuilt \
 			tools-common-prebuilt \
 			sdk-common \
-			junit
+			junit-host
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/tools/layoutlib/create/tests/Android.mk b/tools/layoutlib/create/tests/Android.mk
index dafb9c6..61e381d 100644
--- a/tools/layoutlib/create/tests/Android.mk
+++ b/tools/layoutlib/create/tests/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_MODULE := layoutlib-create-tests
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_JAVA_LIBRARIES := layoutlib_create junit
+LOCAL_JAVA_LIBRARIES := layoutlib_create junit-host
 LOCAL_STATIC_JAVA_LIBRARIES := asm-5.0
 
 include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/preload2/Android.mk b/tools/preload2/Android.mk
index 09d95ff..769db6b 100644
--- a/tools/preload2/Android.mk
+++ b/tools/preload2/Android.mk
@@ -12,7 +12,7 @@
 
 # For JDWP access we use the framework in the JDWP tests from Apache Harmony, for
 # convenience (and to not depend on internal JDK APIs).
-LOCAL_STATIC_JAVA_LIBRARIES += apache-harmony-jdwp-tests-host junit
+LOCAL_STATIC_JAVA_LIBRARIES += apache-harmony-jdwp-tests-host junit-host
 
 LOCAL_MODULE:= preload2
 
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 ca5b0e0..c42a19b 100644
--- a/tools/preload2/src/com/android/preload/Main.java
+++ b/tools/preload2/src/com/android/preload/Main.java
@@ -32,12 +32,18 @@
 import com.android.preload.classdataretrieval.ClassDataRetriever;
 import com.android.preload.classdataretrieval.hprof.Hprof;
 import com.android.preload.classdataretrieval.jdwp.JDWPClassDataRetriever;
-import com.android.preload.ui.UI;
+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;
@@ -66,7 +72,7 @@
     private DumpTableModel dataTableModel;
     private DefaultListModel<Client> clientListModel;
 
-    private UI ui;
+    private IUI ui;
 
     // Actions that need to be updated once a device is selected.
     private Collection<DeviceSpecific> deviceSpecificActions;
@@ -85,17 +91,30 @@
             + "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();
-        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();
     }
 
-    public Main() {
+    public Main(IUI ui) {
+        this.ui = ui;
+
         clientListModel = new DefaultListModel<Client>();
         dataTableModel = new DumpTableModel();
 
@@ -124,11 +143,74 @@
             }
         }
 
-        ui = new UI(clientListModel, dataTableModel, actions);
-        ui.setVisible(true);
+        ui.prepare(clientListModel, dataTableModel, actions);
     }
 
-    public static UI getUI() {
+    /**
+     * @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;
     }
 
@@ -176,6 +258,7 @@
         new ReloadListAction(clientUtils, getDevice(), clientListModel).run();
 
         getUI().hideWaitDialog();
+        getUI().ready();
     }
 
     private void initDevice() {
diff --git a/tools/preload2/src/com/android/preload/actions/AbstractThreadedAction.java b/tools/preload2/src/com/android/preload/actions/AbstractThreadedAction.java
index fbf83d2..5787d85 100644
--- a/tools/preload2/src/com/android/preload/actions/AbstractThreadedAction.java
+++ b/tools/preload2/src/com/android/preload/actions/AbstractThreadedAction.java
@@ -16,6 +16,7 @@
 
 package com.android.preload.actions;
 
+import com.android.preload.Main;
 import java.awt.event.ActionEvent;
 
 import javax.swing.AbstractAction;
@@ -28,7 +29,11 @@
 
     @Override
     public void actionPerformed(ActionEvent e) {
-        new Thread(this).start();
+        if (Main.getUI().isSingleThreaded()) {
+            run();
+        } else {
+            new Thread(this).start();
+        }
     }
 
 }
diff --git a/tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java b/tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java
index b524716..3a7f7f7 100644
--- a/tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java
+++ b/tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java
@@ -32,14 +32,13 @@
 import java.util.regex.Pattern;
 
 import javax.swing.AbstractAction;
-import javax.swing.JFileChooser;
 
 /**
  * Compute an intersection of classes from the given data. A class is in the intersection if it
  * appears in at least the number of threshold given packages. An optional blacklist can be
  * used to filter classes from the intersection.
  */
-public class ComputeThresholdAction extends AbstractAction implements Runnable {
+public class ComputeThresholdAction extends AbstractThreadedAction {
     protected int threshold;
     private Pattern blacklist;
     private DumpTableModel dataTableModel;
@@ -72,7 +71,7 @@
             return;
         }
 
-        new Thread(this).start();
+        super.actionPerformed(e);
     }
 
     @Override
@@ -92,10 +91,8 @@
         boolean ret = Main.getUI().showConfirmDialog("Computed a set with " + result.size()
                 + " classes, would you like to save to disk?", "Save?");
         if (ret) {
-            JFileChooser jfc = new JFileChooser();
-            int ret2 = jfc.showSaveDialog(Main.getUI());
-            if (ret2 == JFileChooser.APPROVE_OPTION) {
-                File f = jfc.getSelectedFile();
+            File f = Main.getUI().showSaveDialog();
+            if (f != null) {
                 saveSet(result, f);
             }
         }
diff --git a/tools/preload2/src/com/android/preload/actions/ExportAction.java b/tools/preload2/src/com/android/preload/actions/ExportAction.java
index cb8b3df..848a568 100644
--- a/tools/preload2/src/com/android/preload/actions/ExportAction.java
+++ b/tools/preload2/src/com/android/preload/actions/ExportAction.java
@@ -19,14 +19,11 @@
 import com.android.preload.DumpDataIO;
 import com.android.preload.DumpTableModel;
 import com.android.preload.Main;
-
 import java.awt.event.ActionEvent;
 import java.io.File;
 import java.io.PrintWriter;
 
-import javax.swing.AbstractAction;
-
-public class ExportAction extends AbstractAction implements Runnable {
+public class ExportAction extends AbstractThreadedAction {
     private File lastSaveFile;
     private DumpTableModel dataTableModel;
 
@@ -39,7 +36,7 @@
     public void actionPerformed(ActionEvent e) {
         lastSaveFile = Main.getUI().showSaveDialog();
         if (lastSaveFile != null) {
-            new Thread(this).start();
+            super.actionPerformed(e);
         }
     }
 
diff --git a/tools/preload2/src/com/android/preload/actions/ImportAction.java b/tools/preload2/src/com/android/preload/actions/ImportAction.java
index 5c19765..bfeeb83 100644
--- a/tools/preload2/src/com/android/preload/actions/ImportAction.java
+++ b/tools/preload2/src/com/android/preload/actions/ImportAction.java
@@ -27,7 +27,7 @@
 
 import javax.swing.AbstractAction;
 
-public class ImportAction extends AbstractAction implements Runnable {
+public class ImportAction extends AbstractThreadedAction {
     private File[] lastOpenFiles;
     private DumpTableModel dataTableModel;
 
@@ -40,7 +40,7 @@
     public void actionPerformed(ActionEvent e) {
         lastOpenFiles = Main.getUI().showOpenDialog(true);
         if (lastOpenFiles != null) {
-            new Thread(this).start();
+            super.actionPerformed(e);
         }
     }
 
diff --git a/tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java b/tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java
index 385e857..29464fc 100644
--- a/tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java
+++ b/tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java
@@ -58,7 +58,12 @@
         if (packages.isEmpty()) {
             packages = DEFAULT_MONKEY_PACKAGES;
         }
-        new Thread(new RunMonkeyRunnable(packages)).start();
+        Runnable r = new RunMonkeyRunnable(packages);
+        if (Main.getUI().isSingleThreaded()) {
+            r.run();
+        } else {
+            new Thread(r).start();
+        }
     }
 
     private class RunMonkeyRunnable implements Runnable {
diff --git a/tools/preload2/src/com/android/preload/ui/IUI.java b/tools/preload2/src/com/android/preload/ui/IUI.java
new file mode 100644
index 0000000..9371463
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/ui/IUI.java
@@ -0,0 +1,45 @@
+package com.android.preload.ui;
+
+import com.android.ddmlib.Client;
+import java.io.File;
+import java.util.List;
+import javax.swing.Action;
+import javax.swing.ListModel;
+import javax.swing.table.TableModel;
+
+/**
+ * UI abstraction for the tool. This allows a graphical mode, command line mode,
+ * or silent mode.
+ */
+public interface IUI {
+
+    void prepare(ListModel<Client> clientListModel, TableModel dataTableModel,
+            List<Action> actions);
+
+    void ready();
+
+    boolean isSingleThreaded();
+
+    Client getSelectedClient();
+
+    int getSelectedDataTableRow();
+
+    void showWaitDialog();
+
+    void updateWaitDialog(String s);
+
+    void hideWaitDialog();
+
+    void showMessageDialog(String s);
+
+    boolean showConfirmDialog(String title, String message);
+
+    String showInputDialog(String message);
+
+    <T> T showChoiceDialog(String title, String message, T[] choices);
+
+    File showSaveDialog();
+
+    File[] showOpenDialog(boolean multi);
+
+}
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/tools/preload2/src/com/android/preload/ui/UI.java b/tools/preload2/src/com/android/preload/ui/SwingUI.java
similarity index 93%
rename from tools/preload2/src/com/android/preload/ui/UI.java
rename to tools/preload2/src/com/android/preload/ui/SwingUI.java
index 47174dd..cab3744 100644
--- a/tools/preload2/src/com/android/preload/ui/UI.java
+++ b/tools/preload2/src/com/android/preload/ui/SwingUI.java
@@ -41,7 +41,7 @@
 import javax.swing.SwingUtilities;
 import javax.swing.table.TableModel;
 
-public class UI extends JFrame {
+public class SwingUI extends JFrame implements IUI {
 
     private JList<Client> clientList;
     private JTable dataTable;
@@ -49,11 +49,18 @@
     // Shared file chooser, means the directory is retained.
     private JFileChooser jfc;
 
-    public UI(ListModel<Client> clientListModel,
-              TableModel dataTableModel,
-              List<Action> actions) {
+    public SwingUI() {
         super("Preloaded-classes computation");
+    }
 
+    @Override
+    public boolean isSingleThreaded() {
+        return false;
+    }
+
+    @Override
+    public void prepare(ListModel<Client> clientListModel, TableModel dataTableModel,
+            List<Action> actions) {
         getContentPane().add(new JScrollPane(clientList = new JList<Client>(clientListModel)),
                 BorderLayout.WEST);
         clientList.setCellRenderer(new ClientListCellRenderer());
@@ -74,18 +81,27 @@
 
         setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         setBounds(100, 100, 800, 600);
+
+        setVisible(true);
     }
 
+    @Override
+    public void ready() {
+    }
+
+    @Override
     public Client getSelectedClient() {
         return clientList.getSelectedValue();
     }
 
+    @Override
     public int getSelectedDataTableRow() {
         return dataTable.getSelectedRow();
     }
 
     private JDialog currentWaitDialog = null;
 
+    @Override
     public void showWaitDialog() {
         if (currentWaitDialog == null) {
             currentWaitDialog = new JDialog(this, "Please wait...", true);
@@ -111,6 +127,7 @@
         });
     }
 
+    @Override
     public void updateWaitDialog(String s) {
         if (currentWaitDialog != null) {
             ((JLabel) currentWaitDialog.getContentPane().getComponent(0)).setText(s);
@@ -124,6 +141,7 @@
         }
     }
 
+    @Override
     public void hideWaitDialog() {
         if (currentWaitDialog != null) {
             currentWaitDialog.setVisible(false);
@@ -131,6 +149,7 @@
         }
     }
 
+    @Override
     public void showMessageDialog(String s) {
         // Hide the wait dialog...
         if (currentWaitDialog != null) {
@@ -147,6 +166,7 @@
         }
     }
 
+    @Override
     public boolean showConfirmDialog(String title, String message) {
         // Hide the wait dialog...
         if (currentWaitDialog != null) {
@@ -164,6 +184,7 @@
         }
     }
 
+    @Override
     public String showInputDialog(String message) {
         // Hide the wait dialog...
         if (currentWaitDialog != null) {
@@ -180,6 +201,7 @@
         }
     }
 
+    @Override
     @SuppressWarnings("unchecked")
     public <T> T showChoiceDialog(String title, String message, T[] choices) {
         // Hide the wait dialog...
@@ -203,6 +225,7 @@
         }
     }
 
+    @Override
     public File showSaveDialog() {
         // Hide the wait dialog...
         if (currentWaitDialog != null) {
@@ -228,6 +251,7 @@
         }
     }
 
+    @Override
     public File[] showOpenDialog(boolean multi) {
         // Hide the wait dialog...
         if (currentWaitDialog != null) {
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