Merge "[QS] Override/add long click accessibility action" into pi-dev
diff --git a/apct-tests/perftests/core/AndroidTest.xml b/apct-tests/perftests/core/AndroidTest.xml
new file mode 100644
index 0000000..6aa34a6
--- /dev/null
+++ b/apct-tests/perftests/core/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs CorePerfTests metric instrumentation.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-metric-instrumentation" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CorePerfTests.apk" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.perftests.core" />
+    </test>
+</configuration>
diff --git a/apct-tests/perftests/multiuser/Android.mk b/apct-tests/perftests/multiuser/Android.mk
index a803369..9bc7d05 100644
--- a/apct-tests/perftests/multiuser/Android.mk
+++ b/apct-tests/perftests/multiuser/Android.mk
@@ -26,6 +26,8 @@
 LOCAL_PACKAGE_NAME := MultiUserPerfTests
 LOCAL_PRIVATE_PLATFORM_APIS := true
 
+LOCAL_COMPATIBILITY_SUITE += device-tests
+
 LOCAL_CERTIFICATE := platform
 
 include $(BUILD_PACKAGE)
diff --git a/apct-tests/perftests/multiuser/AndroidTest.xml b/apct-tests/perftests/multiuser/AndroidTest.xml
new file mode 100644
index 0000000..6ede827
--- /dev/null
+++ b/apct-tests/perftests/multiuser/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs MultiUserPerfTests metric instrumentation.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-metric-instrumentation" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="MultiUserPerfTests.apk" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.perftests.multiuser" />
+    </test>
+</configuration>
diff --git a/api/current.txt b/api/current.txt
index 670f6ca..4a60314 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6468,7 +6468,6 @@
     method public java.lang.CharSequence getOrganizationName(android.content.ComponentName);
     method public java.util.List<android.telephony.data.ApnSetting> getOverrideApns(android.content.ComponentName);
     method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
-    method public java.lang.String getPasswordBlacklistName(android.content.ComponentName);
     method public long getPasswordExpiration(android.content.ComponentName);
     method public long getPasswordExpirationTimeout(android.content.ComponentName);
     method public int getPasswordHistoryLength(android.content.ComponentName);
@@ -6577,7 +6576,6 @@
     method public void setOrganizationName(android.content.ComponentName, java.lang.CharSequence);
     method public void setOverrideApnsEnabled(android.content.ComponentName, boolean);
     method public java.lang.String[] setPackagesSuspended(android.content.ComponentName, java.lang.String[], boolean);
-    method public boolean setPasswordBlacklist(android.content.ComponentName, java.lang.String, java.util.List<java.lang.String>);
     method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
     method public void setPasswordHistoryLength(android.content.ComponentName, int);
     method public void setPasswordMinimumLength(android.content.ComponentName, int);
@@ -7219,6 +7217,7 @@
     field public static final java.lang.String HINT_LIST_ITEM = "list_item";
     field public static final java.lang.String HINT_NO_TINT = "no_tint";
     field public static final java.lang.String HINT_PARTIAL = "partial";
+    field public static final java.lang.String HINT_PERMISSION_REQUEST = "permission_request";
     field public static final java.lang.String HINT_SEE_MORE = "see_more";
     field public static final java.lang.String HINT_SELECTED = "selected";
     field public static final java.lang.String HINT_SHORTCUT = "shortcut";
@@ -13645,21 +13644,22 @@
     method public int getAllocator();
     method public boolean getConserveMemory();
     method public android.graphics.Rect getCrop();
-    method public boolean getDecodeAsAlphaMask();
-    method public boolean getMutable();
     method public android.graphics.ImageDecoder.OnPartialImageListener getOnPartialImageListener();
     method public android.graphics.PostProcessor getPostProcessor();
-    method public boolean getRequireUnpremultiplied();
+    method public boolean isDecodeAsAlphaMaskEnabled();
+    method public boolean isMutableRequired();
+    method public boolean isUnpremultipliedRequired();
     method public android.graphics.ImageDecoder setAllocator(int);
     method public android.graphics.ImageDecoder setConserveMemory(boolean);
     method public android.graphics.ImageDecoder setCrop(android.graphics.Rect);
-    method public android.graphics.ImageDecoder setDecodeAsAlphaMask(boolean);
-    method public android.graphics.ImageDecoder setMutable(boolean);
+    method public android.graphics.ImageDecoder setDecodeAsAlphaMaskEnabled(boolean);
+    method public android.graphics.ImageDecoder setMutableRequired(boolean);
     method public android.graphics.ImageDecoder setOnPartialImageListener(android.graphics.ImageDecoder.OnPartialImageListener);
     method public android.graphics.ImageDecoder setPostProcessor(android.graphics.PostProcessor);
-    method public android.graphics.ImageDecoder setRequireUnpremultiplied(boolean);
-    method public android.graphics.ImageDecoder setSampleSize(int);
+    method public android.graphics.ImageDecoder setTargetColorSpace(android.graphics.ColorSpace);
+    method public android.graphics.ImageDecoder setTargetSampleSize(int);
     method public android.graphics.ImageDecoder setTargetSize(int, int);
+    method public android.graphics.ImageDecoder setUnpremultipliedRequired(boolean);
     field public static final int ALLOCATOR_DEFAULT = 0; // 0x0
     field public static final int ALLOCATOR_HARDWARE = 3; // 0x3
     field public static final int ALLOCATOR_SHARED_MEMORY = 2; // 0x2
@@ -13675,6 +13675,7 @@
   }
 
   public static class ImageDecoder.ImageInfo {
+    method public android.graphics.ColorSpace getColorSpace();
     method public java.lang.String getMimeType();
     method public android.util.Size getSize();
     method public boolean isAnimated();
@@ -24009,6 +24010,7 @@
     field public static final int MEDIA_INFO_BUFFERING_START = 701; // 0x2bd
     field public static final int MEDIA_INFO_METADATA_UPDATE = 802; // 0x322
     field public static final int MEDIA_INFO_NOT_SEEKABLE = 801; // 0x321
+    field public static final int MEDIA_INFO_STARTED_AS_NEXT = 2; // 0x2
     field public static final int MEDIA_INFO_SUBTITLE_TIMED_OUT = 902; // 0x386
     field public static final int MEDIA_INFO_UNKNOWN = 1; // 0x1
     field public static final int MEDIA_INFO_UNSUPPORTED_SUBTITLE = 901; // 0x385
@@ -27138,6 +27140,7 @@
     method public void bindSocket(java.net.Socket) throws java.io.IOException;
     method public void bindSocket(java.io.FileDescriptor) throws java.io.IOException;
     method public int describeContents();
+    method public static android.net.Network fromNetworkHandle(long);
     method public java.net.InetAddress[] getAllByName(java.lang.String) throws java.net.UnknownHostException;
     method public java.net.InetAddress getByName(java.lang.String) throws java.net.UnknownHostException;
     method public long getNetworkHandle();
@@ -50417,9 +50420,9 @@
     ctor public TextClassification.Options();
     method public int describeContents();
     method public android.os.LocaleList getDefaultLocales();
-    method public java.util.Calendar getReferenceTime();
+    method public java.time.ZonedDateTime getReferenceTime();
     method public android.view.textclassifier.TextClassification.Options setDefaultLocales(android.os.LocaleList);
-    method public android.view.textclassifier.TextClassification.Options setReferenceTime(java.util.Calendar);
+    method public android.view.textclassifier.TextClassification.Options setReferenceTime(java.time.ZonedDateTime);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassification.Options> CREATOR;
   }
diff --git a/api/removed.txt b/api/removed.txt
index 5863e77..2d76c5a 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -183,7 +183,13 @@
 
   public final class ImageDecoder implements java.lang.AutoCloseable {
     method public deprecated boolean getAsAlphaMask();
+    method public deprecated boolean getDecodeAsAlphaMask();
+    method public deprecated boolean getMutable();
+    method public deprecated boolean getRequireUnpremultiplied();
     method public deprecated android.graphics.ImageDecoder setAsAlphaMask(boolean);
+    method public deprecated android.graphics.ImageDecoder setDecodeAsAlphaMask(boolean);
+    method public deprecated android.graphics.ImageDecoder setMutable(boolean);
+    method public deprecated android.graphics.ImageDecoder setRequireUnpremultiplied(boolean);
     method public deprecated android.graphics.ImageDecoder setResize(int, int);
     method public deprecated android.graphics.ImageDecoder setResize(int);
     field public static final deprecated int ERROR_SOURCE_ERROR = 3; // 0x3
diff --git a/api/system-current.txt b/api/system-current.txt
index a81afed5..ed763ba 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -57,6 +57,7 @@
     field public static final java.lang.String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
     field public static final java.lang.String CONNECTIVITY_INTERNAL = "android.permission.CONNECTIVITY_INTERNAL";
     field public static final java.lang.String CONNECTIVITY_USE_RESTRICTED_NETWORKS = "android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS";
+    field public static final java.lang.String CONTROL_DISPLAY_SATURATION = "android.permission.CONTROL_DISPLAY_SATURATION";
     field public static final java.lang.String CONTROL_INCALL_EXPERIENCE = "android.permission.CONTROL_INCALL_EXPERIENCE";
     field public static final java.lang.String CONTROL_LOCATION_UPDATES = "android.permission.CONTROL_LOCATION_UPDATES";
     field public static final java.lang.String CONTROL_VPN = "android.permission.CONTROL_VPN";
@@ -1252,6 +1253,7 @@
     method public android.hardware.display.BrightnessConfiguration getDefaultBrightnessConfiguration();
     method public android.graphics.Point getStableDisplaySize();
     method public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
+    method public void setSaturationLevel(float);
   }
 
 }
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 3b57d34..d964651 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -319,8 +319,10 @@
         index++;  // look at the next file.
     }
     VLOG("GZipSection is using file %s, fd=%d", mFilenames[index], fd.get());
-    if (fd.get() == -1) return -1;
-
+    if (fd.get() == -1) {
+      ALOGW("GZipSection %s can't open all the files", this->name.string());
+      return NO_ERROR; // e.g. LAST_KMSG will reach here in user build.
+    }
     FdBuffer buffer;
     Fpipe p2cPipe;
     Fpipe c2pPipe;
diff --git a/cmds/incidentd/tests/PrivacyBuffer_test.cpp b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
index 5edc0c7..d129269 100644
--- a/cmds/incidentd/tests/PrivacyBuffer_test.cpp
+++ b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
@@ -38,7 +38,7 @@
 const uint8_t MESSAGE_TYPE = 11;
 const string STRING_FIELD_0 = "\x02\viamtestdata";
 const string VARINT_FIELD_1 = "\x08\x96\x01";  // 150
-const string STRING_FIELD_2 = "\x12\vwhatthefuck";
+const string STRING_FIELD_2 = "\x12\vandroidwins";
 const string FIX64_FIELD_3 = "\x19\xff\xff\xff\xff\xff\xff\xff\xff";  // -1
 const string FIX32_FIELD_4 = "\x25\xff\xff\xff\xff";                  // -1
 const string MESSAGE_FIELD_5 = "\x2a\x10" + VARINT_FIELD_1 + STRING_FIELD_2;
@@ -274,4 +274,4 @@
     autoMsg->children = list;
     string expected = "\x2a\xd" + STRING_FIELD_2;
     assertStripByFields(DEST_AUTOMATIC, expected, 1, autoMsg);
-}
\ No newline at end of file
+}
diff --git a/cmds/incidentd/tests/Section_test.cpp b/cmds/incidentd/tests/Section_test.cpp
index f93839b..2f6698b 100644
--- a/cmds/incidentd/tests/Section_test.cpp
+++ b/cmds/incidentd/tests/Section_test.cpp
@@ -19,6 +19,7 @@
 #include <android-base/file.h>
 #include <android-base/test_utils.h>
 #include <android/os/IncidentReportArgs.h>
+#include <android/util/protobuf.h>
 #include <frameworks/base/libs/incident/proto/android/os/header.pb.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -31,12 +32,13 @@
 const int QUICK_TIMEOUT_MS = 100;
 
 const string VARINT_FIELD_1 = "\x08\x96\x01";  // 150
-const string STRING_FIELD_2 = "\x12\vwhatthefuck";
+const string STRING_FIELD_2 = "\x12\vandroidwins";
 const string FIX64_FIELD_3 = "\x19\xff\xff\xff\xff\xff\xff\xff\xff";  // -1
 
 using namespace android::base;
 using namespace android::binder;
 using namespace android::os;
+using namespace android::util;
 using namespace std;
 using ::testing::StrEq;
 using ::testing::Test;
@@ -154,17 +156,26 @@
     requests.setMainDest(android::os::DEST_LOCAL);
 
     ASSERT_EQ(NO_ERROR, gs.Execute(&requests));
-    std::string expect, gzFile, actual;
+    std::string expected, gzFile, actual;
     ASSERT_TRUE(ReadFileToString(testGzFile, &gzFile));
     ASSERT_TRUE(ReadFileToString(tf.path, &actual));
-    expect = "\x2\xC6\x6\n\"" + testFile + "\x12\x9F\x6" + gzFile;
-    EXPECT_THAT(actual, StrEq(expect));
+    // generates the expected protobuf result.
+    size_t fileLen = testFile.size();
+    size_t totalLen = 1 + get_varint_size(fileLen) + fileLen + 3 + gzFile.size();
+    uint8_t header[20];
+    header[0] = '\x2'; // header 0 << 3 + 2
+    uint8_t* ptr = write_raw_varint(header + 1, totalLen);
+    *ptr = '\n'; // header 1 << 3 + 2
+    ptr = write_raw_varint(++ptr, fileLen);
+    expected.assign((const char*)header, ptr - header);
+    expected += testFile + "\x12\x9F\x6" + gzFile;
+    EXPECT_THAT(actual, StrEq(expected));
 }
 
 TEST_F(SectionTest, GZipSectionNoFileFound) {
     GZipSection gs(NOOP_PARSER, "/tmp/nonexist1", "/tmp/nonexist2", NULL);
     requests.setMainFd(STDOUT_FILENO);
-    ASSERT_EQ(-1, gs.Execute(&requests));
+    ASSERT_EQ(NO_ERROR, gs.Execute(&requests));
 }
 
 TEST_F(SectionTest, CommandSectionConstructor) {
diff --git a/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java b/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
index b76d669..37b7acf 100644
--- a/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
+++ b/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
@@ -29,23 +29,21 @@
     private String[] mArgs;
     private int mNextArg;
     private String mCurArgData;
-    private boolean mIsForegroundRequest;
+
+    private int mExemptionFlag = ContentResolver.SYNC_EXEMPTION_NONE;
 
     enum Operation {
         REQUEST_SYNC {
             @Override
             void invoke(RequestSync caller) {
-                if (caller.mIsForegroundRequest) {
-                    caller.mExtras.putBoolean(
-                            ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC, true);
-                } else {
-                    caller.mExtras.putBoolean(
-                            ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_BG_SYNC, true);
+                final int flag = caller.mExemptionFlag;
+                caller.mExtras.putInt(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG, flag);
+                if (flag == ContentResolver.SYNC_EXEMPTION_NONE) {
                     System.out.println(
                             "Making a sync request as a background app.\n"
                             + "Note: request may be throttled by App Standby.\n"
                             + "To override this behavior and run a sync immediately,"
-                            + " pass a -f option.\n");
+                            + " pass a -f or -F option (use -h for help).\n");
                 }
                 final SyncRequest request =
                         new SyncRequest.Builder()
@@ -213,7 +211,10 @@
                 mExtras.putBoolean(key, Boolean.valueOf(value));
 
             } else if (opt.equals("-f") || opt.equals("--foreground")) {
-                mIsForegroundRequest = true;
+                mExemptionFlag = ContentResolver.SYNC_EXEMPTION_ACTIVE;
+
+            } else if (opt.equals("-F") || opt.equals("--top")) {
+                mExemptionFlag = ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP;
 
             } else {
                 System.err.println("Error: Unknown option: " + opt);
@@ -293,7 +294,9 @@
                 "       -a|--authority <AUTHORITY>\n" +
                 "    App-standby related options\n" +
                 "\n" +
-                "       -f|--foreground (Exempt a sync from app standby)\n" +
+                "       -f|--foreground (cause WORKING_SET, FREQUENT sync adapters" +
+                        " to run immediately)\n" +
+                "       -F|--top (cause even RARE sync adapters to run immediately)\n" +
                 "    ContentResolver extra options:\n" +
                 "      --is|--ignore-settings: Add SYNC_EXTRAS_IGNORE_SETTINGS\n" +
                 "      --ib|--ignore-backoff: Add SYNC_EXTRAS_IGNORE_BACKOFF\n" +
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 5e75359..cfb9d87 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -245,7 +245,7 @@
  * Logs when the ble scan state changes.
  *
  * Logged from:
- *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ *   packages/apps/Bluetooth/src/com/android/bluetooth/gatt/AppScanStats.java
  */
 // TODO: Consider changing to tracking per-scanner-id (log from AppScanStats).
 message BleScanStateChanged {
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index bd3c78c..d0f510d 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -312,8 +312,13 @@
 
     if (mPullTagId != -1) { // for pulled events
         if (mCondition == true) {
-            interval.start = value;
-            interval.startUpdated = true;
+            if (!interval.startUpdated) {
+                interval.start = value;
+                interval.startUpdated = true;
+            } else {
+                // skip it if there is already value recorded for the start
+                VLOG("Already recorded value for this dimension %s", eventKey.toString().c_str());
+            }
         } else {
             // Generally we expect value to be monotonically increasing.
             // If not, there was a reset event. We take the absolute value as
@@ -382,6 +387,7 @@
     int tainted = 0;
     for (const auto& slice : mCurrentSlicedBucket) {
         tainted += slice.second.tainted;
+        tainted += slice.second.startUpdated;
         info.mValue = slice.second.sum;
         // it will auto create new vector of ValuebucketInfo if the key is not found.
         auto& bucketList = mPastBuckets[slice.first];
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index ebc6e81..45d9531 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -159,6 +159,10 @@
     FRIEND_TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade);
     FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition);
     FRIEND_TEST(ValueMetricProducerTest, TestAnomalyDetection);
+    FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition);
+    FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition);
+    FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2);
+    FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition3);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index a0224ec..c650a06 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -45,6 +45,8 @@
 const int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
 const int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
 const int64_t bucket4StartTimeNs = bucketStartTimeNs + 3 * bucketSizeNs;
+const int64_t bucket5StartTimeNs = bucketStartTimeNs + 4 * bucketSizeNs;
+const int64_t bucket6StartTimeNs = bucketStartTimeNs + 5 * bucketSizeNs;
 const int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
 
 /*
@@ -431,6 +433,376 @@
             std::ceil(1.0 * event6->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
 }
 
+// Test value metric no condition, the pull on bucket boundary come in time and too late
+TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    shared_ptr<MockStatsPullerManager> pullerManager =
+            make_shared<StrictMock<MockStatsPullerManager>>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      tagId, bucketStartTimeNs, pullerManager);
+    valueProducer.setBucketSize(60 * NS_PER_SEC);
+
+    vector<shared_ptr<LogEvent>> allData;
+    // pull 1
+    allData.clear();
+    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+    event->write(tagId);
+    event->write(11);
+    event->init();
+    allData.push_back(event);
+
+    valueProducer.onDataPulled(allData);
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+    valueProducer.setBucketSize(60 * NS_PER_SEC);
+
+    // startUpdated:true tainted:0 sum:0 start:11
+    EXPECT_EQ(true, curInterval.startUpdated);
+    EXPECT_EQ(0, curInterval.tainted);
+    EXPECT_EQ(0, curInterval.sum);
+    EXPECT_EQ(11, curInterval.start);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(0, valueProducer.mPastBuckets.begin()->second.back().mValue);
+
+    // pull 2 at correct time
+    allData.clear();
+    event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
+    event->write(tagId);
+    event->write(23);
+    event->init();
+    allData.push_back(event);
+    valueProducer.onDataPulled(allData);
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+    // tartUpdated:false tainted:0 sum:12
+    EXPECT_EQ(true, curInterval.startUpdated);
+    EXPECT_EQ(0, curInterval.tainted);
+    EXPECT_EQ(0, curInterval.sum);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
+    EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().mValue);
+
+    // pull 3 come late.
+    // The previous bucket gets closed with error. (Has start value 23, no ending)
+    // Another bucket gets closed with error. (No start, but ending with 36)
+    // The new bucket is back to normal.
+    allData.clear();
+    event = make_shared<LogEvent>(tagId, bucket6StartTimeNs + 1);
+    event->write(tagId);
+    event->write(36);
+    event->init();
+    allData.push_back(event);
+    valueProducer.onDataPulled(allData);
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+    // startUpdated:false tainted:0 sum:12
+    EXPECT_EQ(true, curInterval.startUpdated);
+    EXPECT_EQ(0, curInterval.tainted);
+    EXPECT_EQ(36, curInterval.start);
+    EXPECT_EQ(0, curInterval.sum);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(4UL, valueProducer.mPastBuckets.begin()->second.size());
+    EXPECT_EQ(0, valueProducer.mPastBuckets.begin()->second[0].mValue);
+    EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second[1].mValue);
+    EXPECT_EQ(0, valueProducer.mPastBuckets.begin()->second[2].mValue);
+    EXPECT_EQ(0, valueProducer.mPastBuckets.begin()->second[3].mValue);
+}
+
+/*
+ * Test pulled event with non sliced condition. The pull on boundary come late because the alarm
+ * was delivered late.
+ */
+TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+    metric.set_condition(StringToId("SCREEN_ON"));
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    shared_ptr<MockStatsPullerManager> pullerManager =
+            make_shared<StrictMock<MockStatsPullerManager>>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+    EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
+            // condition becomes true
+            .WillOnce(Invoke([](int tagId, int64_t timeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+                event->write(tagId);
+                event->write(100);
+                event->init();
+                data->push_back(event);
+                return true;
+            }))
+            // condition becomes false
+            .WillOnce(Invoke([](int tagId, int64_t timeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 20);
+                event->write(tagId);
+                event->write(120);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs,
+                                      pullerManager);
+    valueProducer.setBucketSize(60 * NS_PER_SEC);
+    valueProducer.onConditionChanged(true, bucketStartTimeNs + 8);
+
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+    // startUpdated:false tainted:0 sum:0 start:100
+    EXPECT_EQ(100, curInterval.start);
+    EXPECT_EQ(true, curInterval.startUpdated);
+    EXPECT_EQ(0, curInterval.tainted);
+    EXPECT_EQ(0, curInterval.sum);
+    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+
+    // pull on bucket boundary come late, condition change happens before it
+    valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1);
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+    EXPECT_EQ(false, curInterval.startUpdated);
+    EXPECT_EQ(1, curInterval.tainted);
+    EXPECT_EQ(0, curInterval.sum);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
+    EXPECT_EQ(0, valueProducer.mPastBuckets.begin()->second[0].mValue);
+
+    // Now the alarm is delivered.
+    // since the condition turned to off before this pull finish, it has no effect
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 30);
+    event->write(1);
+    event->write(110);
+    event->init();
+    allData.push_back(event);
+    valueProducer.onDataPulled(allData);
+
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+    EXPECT_EQ(false, curInterval.startUpdated);
+    EXPECT_EQ(1, curInterval.tainted);
+    EXPECT_EQ(0, curInterval.sum);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
+    EXPECT_EQ(0, valueProducer.mPastBuckets.begin()->second[0].mValue);
+}
+
+/*
+ * Test pulled event with non sliced condition. The pull on boundary come late, after the condition
+ * change to false, and then true again. This is due to alarm delivered late.
+ */
+TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+    metric.set_condition(StringToId("SCREEN_ON"));
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    shared_ptr<MockStatsPullerManager> pullerManager =
+            make_shared<StrictMock<MockStatsPullerManager>>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillRepeatedly(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+    EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
+            // condition becomes true
+            .WillOnce(Invoke([](int tagId, int64_t timeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+                event->write(tagId);
+                event->write(100);
+                event->init();
+                data->push_back(event);
+                return true;
+            }))
+            // condition becomes false
+            .WillOnce(Invoke([](int tagId, int64_t timeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 20);
+                event->write(tagId);
+                event->write(120);
+                event->init();
+                data->push_back(event);
+                return true;
+            }))
+            // condition becomes true again
+            .WillOnce(Invoke([](int tagId, int64_t timeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 30);
+                event->write(tagId);
+                event->write(130);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs,
+                                      pullerManager);
+    valueProducer.setBucketSize(60 * NS_PER_SEC);
+    valueProducer.onConditionChanged(true, bucketStartTimeNs + 8);
+
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+    // startUpdated:false tainted:0 sum:0 start:100
+    EXPECT_EQ(100, curInterval.start);
+    EXPECT_EQ(true, curInterval.startUpdated);
+    EXPECT_EQ(0, curInterval.tainted);
+    EXPECT_EQ(0, curInterval.sum);
+    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+
+    // pull on bucket boundary come late, condition change happens before it
+    valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1);
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+    EXPECT_EQ(false, curInterval.startUpdated);
+    EXPECT_EQ(1, curInterval.tainted);
+    EXPECT_EQ(0, curInterval.sum);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
+    EXPECT_EQ(0, valueProducer.mPastBuckets.begin()->second[0].mValue);
+
+    // condition changed to true again, before the pull alarm is delivered
+    valueProducer.onConditionChanged(true, bucket2StartTimeNs + 25);
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+    EXPECT_EQ(true, curInterval.startUpdated);
+    EXPECT_EQ(130, curInterval.start);
+    EXPECT_EQ(1, curInterval.tainted);
+    EXPECT_EQ(0, curInterval.sum);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
+    EXPECT_EQ(0, valueProducer.mPastBuckets.begin()->second[0].mValue);
+
+    // Now the alarm is delivered, but it is considered late, it has no effect
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 50);
+    event->write(1);
+    event->write(110);
+    event->init();
+    allData.push_back(event);
+    valueProducer.onDataPulled(allData);
+
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+    EXPECT_EQ(true, curInterval.startUpdated);
+    EXPECT_EQ(130, curInterval.start);
+    EXPECT_EQ(1, curInterval.tainted);
+    EXPECT_EQ(0, curInterval.sum);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
+    EXPECT_EQ(0, valueProducer.mPastBuckets.begin()->second[0].mValue);
+}
+
+/*
+ * Test pulled event with non sliced condition. The pull on boundary come late because the puller is
+ * very slow.
+ */
+TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition3) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+    metric.set_condition(StringToId("SCREEN_ON"));
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    shared_ptr<MockStatsPullerManager> pullerManager =
+            make_shared<StrictMock<MockStatsPullerManager>>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+    EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
+            // condition becomes true
+            .WillOnce(Invoke([](int tagId, int64_t timeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+                event->write(tagId);
+                event->write(100);
+                event->init();
+                data->push_back(event);
+                return true;
+            }))
+            // condition becomes false
+            .WillOnce(Invoke([](int tagId, int64_t timeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 20);
+                event->write(tagId);
+                event->write(120);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs,
+                                      pullerManager);
+    valueProducer.setBucketSize(60 * NS_PER_SEC);
+    valueProducer.onConditionChanged(true, bucketStartTimeNs + 8);
+
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+    // startUpdated:false tainted:0 sum:0 start:100
+    EXPECT_EQ(100, curInterval.start);
+    EXPECT_EQ(true, curInterval.startUpdated);
+    EXPECT_EQ(0, curInterval.tainted);
+    EXPECT_EQ(0, curInterval.sum);
+    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+
+    // pull on bucket boundary come late, condition change happens before it.
+    // But puller is very slow in this one, so the data come after bucket finish
+    valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1);
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+    EXPECT_EQ(false, curInterval.startUpdated);
+    EXPECT_EQ(1, curInterval.tainted);
+    EXPECT_EQ(0, curInterval.sum);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
+    EXPECT_EQ(0, valueProducer.mPastBuckets.begin()->second[0].mValue);
+
+    // Alarm is delivered in time, but the pull is very slow, and pullers are called in order,
+    // so this one comes even later
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 30);
+    event->write(1);
+    event->write(110);
+    event->init();
+    allData.push_back(event);
+    valueProducer.onDataPulled(allData);
+
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+    EXPECT_EQ(false, curInterval.startUpdated);
+    EXPECT_EQ(1, curInterval.tainted);
+    EXPECT_EQ(0, curInterval.sum);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
+    EXPECT_EQ(0, valueProducer.mPastBuckets.begin()->second[0].mValue);
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 70e3fad..015c4b6 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -7,6 +7,7 @@
 Landroid/animation/ValueAnimator;->sDurationScale:F
 Landroid/app/Activity;->getActivityOptions()Landroid/app/ActivityOptions;
 Landroid/app/Activity;->getActivityToken()Landroid/os/IBinder;
+Landroid/app/ActivityGroup;->mLocalActivityManager:Landroid/app/LocalActivityManager;
 Landroid/app/Activity;->mActivityInfo:Landroid/content/pm/ActivityInfo;
 Landroid/app/ActivityManager;->clearApplicationUserData(Ljava/lang/String;Landroid/content/pm/IPackageDataObserver;)Z
 Landroid/app/ActivityManager;->getMaxRecentTasksStatic()I
@@ -63,8 +64,10 @@
 Landroid/app/ActivityThread$AppBindData;->appInfo:Landroid/content/pm/ApplicationInfo;
 Landroid/app/ActivityThread$AppBindData;->info:Landroid/app/LoadedApk;
 Landroid/app/ActivityThread$AppBindData;->instrumentationArgs:Landroid/os/Bundle;
+Landroid/app/ActivityThread$AppBindData;->persistent:Z
 Landroid/app/ActivityThread$AppBindData;->processName:Ljava/lang/String;
 Landroid/app/ActivityThread$AppBindData;->providers:Ljava/util/List;
+Landroid/app/ActivityThread$AppBindData;->restrictedBackupMode:Z
 Landroid/app/ActivityThread$BindServiceData;->intent:Landroid/content/Intent;
 Landroid/app/ActivityThread$BindServiceData;->token:Landroid/os/IBinder;
 Landroid/app/ActivityThread$CreateServiceData;->compatInfo:Landroid/content/res/CompatibilityInfo;
@@ -89,11 +92,13 @@
 Landroid/app/ActivityThread$H;->BIND_SERVICE:I
 Landroid/app/ActivityThread$H;->CREATE_SERVICE:I
 Landroid/app/ActivityThread$H;->DUMP_PROVIDER:I
+Landroid/app/ActivityThread$H;->ENTER_ANIMATION_COMPLETE:I
 Landroid/app/ActivityThread$H;->EXIT_APPLICATION:I
 Landroid/app/ActivityThread$H;->GC_WHEN_IDLE:I
 Landroid/app/ActivityThread$H;->INSTALL_PROVIDER:I
 Landroid/app/ActivityThread$H;->RECEIVER:I
 Landroid/app/ActivityThread$H;->REMOVE_PROVIDER:I
+Landroid/app/ActivityThread$H;->SCHEDULE_CRASH:I
 Landroid/app/ActivityThread$H;->SERVICE_ARGS:I
 Landroid/app/ActivityThread$H;->STOP_SERVICE:I
 Landroid/app/ActivityThread$H;->UNBIND_SERVICE:I
@@ -102,6 +107,7 @@
 Landroid/app/ActivityThread;->mActivities:Landroid/util/ArrayMap;
 Landroid/app/ActivityThread;->mAllApplications:Ljava/util/ArrayList;
 Landroid/app/ActivityThread;->mBoundApplication:Landroid/app/ActivityThread$AppBindData;
+Landroid/app/ActivityThread;->mConfiguration:Landroid/content/res/Configuration;
 Landroid/app/ActivityThread;->mDensityCompatMode:Z
 Landroid/app/ActivityThread;->mH:Landroid/app/ActivityThread$H;
 Landroid/app/ActivityThread;->mInitialApplication:Landroid/app/Application;
@@ -110,8 +116,10 @@
 Landroid/app/ActivityThread;->mLocalProviders:Landroid/util/ArrayMap;
 Landroid/app/ActivityThread;->mNumVisibleActivities:I
 Landroid/app/ActivityThread;->mPackages:Landroid/util/ArrayMap;
+Landroid/app/ActivityThread;->mPendingConfiguration:Landroid/content/res/Configuration;
 Landroid/app/ActivityThread;->mProviderMap:Landroid/util/ArrayMap;
 Landroid/app/ActivityThread;->mResourcePackages:Landroid/util/ArrayMap;
+Landroid/app/ActivityThread;->mResourcesManager:Landroid/app/ResourcesManager;
 Landroid/app/ActivityThread;->mServices:Landroid/util/ArrayMap;
 Landroid/app/ActivityThread;->performNewIntents(Landroid/os/IBinder;Ljava/util/List;Z)V
 Landroid/app/ActivityThread;->performStopActivity(Landroid/os/IBinder;ZLjava/lang/String;)V
@@ -146,6 +154,7 @@
 Landroid/app/AlertDialog$Builder;->P:Lcom/android/internal/app/AlertController$AlertParams;
 Landroid/app/AlertDialog;->mAlert:Lcom/android/internal/app/AlertController;
 Landroid/app/AppGlobals;->getInitialApplication()Landroid/app/Application;
+Landroid/app/AppGlobals;->getInitialPackage()Ljava/lang/String;
 Landroid/app/AppGlobals;->getPackageManager()Landroid/content/pm/IPackageManager;
 Landroid/app/Application;->attach(Landroid/content/Context;)V
 Landroid/app/Application;->collectActivityLifecycleCallbacks()[Ljava/lang/Object;
@@ -166,21 +175,26 @@
 Landroid/app/ApplicationPackageManager;->getPackageSizeInfoAsUser(Ljava/lang/String;ILandroid/content/pm/IPackageStatsObserver;)V
 Landroid/app/ApplicationPackageManager;-><init>(Landroid/app/ContextImpl;Landroid/content/pm/IPackageManager;)V
 Landroid/app/ApplicationPackageManager;->mPM:Landroid/content/pm/IPackageManager;
+Landroid/app/ApplicationPackageManager;->shouldShowRequestPermissionRationale(Ljava/lang/String;)Z
 Landroid/app/AppOpsManager;->checkOp(IILjava/lang/String;)I
 Landroid/app/AppOpsManager;->checkOpNoThrow(IILjava/lang/String;)I
 Landroid/app/AppOpsManager;->getOpsForPackage(ILjava/lang/String;[I)Ljava/util/List;
 Landroid/app/AppOpsManager;->mService:Lcom/android/internal/app/IAppOpsService;
 Landroid/app/AppOpsManager;->noteOp(I)I
 Landroid/app/AppOpsManager;->noteOp(IILjava/lang/String;)I
+Landroid/app/AppOpsManager;->OP_AUDIO_NOTIFICATION_VOLUME:I
 Landroid/app/AppOpsManager;->OP_COARSE_LOCATION:I
 Landroid/app/AppOpsManager$OpEntry;->getDuration()I
 Landroid/app/AppOpsManager$OpEntry;->getRejectTime()J
 Landroid/app/AppOpsManager;->OP_FINE_LOCATION:I
 Landroid/app/AppOpsManager;->OP_GET_USAGE_STATS:I
 Landroid/app/AppOpsManager;->OP_POST_NOTIFICATION:I
+Landroid/app/AppOpsManager;->OP_READ_CONTACTS:I
 Landroid/app/AppOpsManager;->OP_READ_PHONE_STATE:I
 Landroid/app/AppOpsManager;->OP_READ_SMS:I
+Landroid/app/AppOpsManager;->OP_VIBRATE:I
 Landroid/app/AppOpsManager;->OP_WIFI_SCAN:I
+Landroid/app/AppOpsManager;->OP_WRITE_CONTACTS:I
 Landroid/app/AppOpsManager;->OP_WRITE_SMS:I
 Landroid/app/AppOpsManager;->permissionToOpCode(Ljava/lang/String;)I
 Landroid/app/AppOpsManager;->strOpToOp(Ljava/lang/String;)I
@@ -204,6 +218,7 @@
 Landroid/app/ContextImpl;->getPreferencesDir()Ljava/io/File;
 Landroid/app/ContextImpl;->getReceiverRestrictedContext()Landroid/content/Context;
 Landroid/app/ContextImpl;->mBasePackageName:Ljava/lang/String;
+Landroid/app/ContextImpl;->mClassLoader:Ljava/lang/ClassLoader;
 Landroid/app/ContextImpl;->mContentResolver:Landroid/app/ContextImpl$ApplicationContentResolver;
 Landroid/app/ContextImpl;->mMainThread:Landroid/app/ActivityThread;
 Landroid/app/ContextImpl;->mOpPackageName:Ljava/lang/String;
@@ -213,6 +228,7 @@
 Landroid/app/ContextImpl;->mResources:Landroid/content/res/Resources;
 Landroid/app/ContextImpl;->mServiceCache:[Ljava/lang/Object;
 Landroid/app/ContextImpl;->mTheme:Landroid/content/res/Resources$Theme;
+Landroid/app/ContextImpl;->mThemeResource:I
 Landroid/app/ContextImpl;->scheduleFinalCleanup(Ljava/lang/String;Ljava/lang/String;)V
 Landroid/app/ContextImpl;->setOuterContext(Landroid/content/Context;)V
 Landroid/app/ContextImpl;->sSharedPrefsCache:Landroid/util/ArrayMap;
@@ -230,10 +246,13 @@
 Landroid/app/Fragment;->mChildFragmentManager:Landroid/app/FragmentManagerImpl;
 Landroid/app/Fragment;->mWho:Ljava/lang/String;
 Landroid/app/IActivityManager;->bindService(Landroid/app/IApplicationThread;Landroid/os/IBinder;Landroid/content/Intent;Ljava/lang/String;Landroid/app/IServiceConnection;ILjava/lang/String;I)I
+Landroid/app/IActivityManager;->broadcastIntent(Landroid/app/IApplicationThread;Landroid/content/Intent;Ljava/lang/String;Landroid/content/IIntentReceiver;ILjava/lang/String;Landroid/os/Bundle;[Ljava/lang/String;ILandroid/os/Bundle;ZZI)I
 Landroid/app/IActivityManager;->finishActivity(Landroid/os/IBinder;ILandroid/content/Intent;I)Z
 Landroid/app/IActivityManager;->finishReceiver(Landroid/os/IBinder;ILjava/lang/String;Landroid/os/Bundle;ZI)V
 Landroid/app/IActivityManager;->forceStopPackage(Ljava/lang/String;I)V
+Landroid/app/IActivityManager;->getIntentSender(ILjava/lang/String;Landroid/os/IBinder;Ljava/lang/String;I[Landroid/content/Intent;[Ljava/lang/String;ILandroid/os/Bundle;I)Landroid/content/IIntentSender;
 Landroid/app/IActivityManager;->getLaunchedFromPackage(Landroid/os/IBinder;)Ljava/lang/String;
+Landroid/app/IActivityManager;->getProviderMimeType(Landroid/net/Uri;I)Ljava/lang/String;
 Landroid/app/IActivityManager;->getTaskForActivity(Landroid/os/IBinder;Z)I
 Landroid/app/IActivityManager;->moveTaskToFront(IILandroid/os/Bundle;)V
 Landroid/app/IActivityManager;->publishContentProviders(Landroid/app/IApplicationThread;Ljava/util/List;)V
@@ -241,16 +260,23 @@
 Landroid/app/IActivityManager;->resumeAppSwitches()V
 Landroid/app/IActivityManager;->setRequestedOrientation(Landroid/os/IBinder;I)V
 Landroid/app/IActivityManager;->setTaskResizeable(II)V
+Landroid/app/IActivityManager;->stopService(Landroid/app/IApplicationThread;Landroid/content/Intent;Ljava/lang/String;I)I
 Landroid/app/IActivityManager$Stub$Proxy;->getConfiguration()Landroid/content/res/Configuration;
 Landroid/app/IActivityManager$Stub$Proxy;->getLaunchedFromUid(Landroid/os/IBinder;)I
+Landroid/app/IActivityManager$Stub$Proxy;->getProcessLimit()I
 Landroid/app/IActivityManager$Stub$Proxy;->getProcessPss([I)[J
 Landroid/app/IActivityManager$Stub$Proxy;->isAppForeground(I)Z
 Landroid/app/IActivityManager$Stub$Proxy;->mRemote:Landroid/os/IBinder;
 Landroid/app/IActivityManager;->unbindService(Landroid/app/IServiceConnection;)Z
+Landroid/app/IActivityManager;->unstableProviderDied(Landroid/os/IBinder;)V
 Landroid/app/IAlarmManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/app/IAlarmManager$Stub;->TRANSACTION_remove:I
 Landroid/app/IAlarmManager$Stub;->TRANSACTION_set:I
 Landroid/app/IApplicationThread;->scheduleTrimMemory(I)V
+Landroid/app/INotificationManager;->cancelAllNotifications(Ljava/lang/String;I)V
+Landroid/app/INotificationManager;->cancelNotificationWithTag(Ljava/lang/String;Ljava/lang/String;II)V
+Landroid/app/INotificationManager;->cancelToast(Ljava/lang/String;Landroid/app/ITransientNotification;)V
+Landroid/app/INotificationManager;->enqueueToast(Ljava/lang/String;Landroid/app/ITransientNotification;I)V
 Landroid/app/INotificationManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/INotificationManager;
 Landroid/app/INotificationManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/app/Instrumentation;->execStartActivities(Landroid/content/Context;Landroid/os/IBinder;Landroid/os/IBinder;Landroid/app/Activity;[Landroid/content/Intent;Landroid/os/Bundle;)V
@@ -258,9 +284,12 @@
 Landroid/app/Instrumentation;->execStartActivity(Landroid/content/Context;Landroid/os/IBinder;Landroid/os/IBinder;Ljava/lang/String;Landroid/content/Intent;ILandroid/os/Bundle;)Landroid/app/Instrumentation$ActivityResult;
 Landroid/app/Instrumentation;->execStartActivity(Landroid/content/Context;Landroid/os/IBinder;Landroid/os/IBinder;Ljava/lang/String;Landroid/content/Intent;ILandroid/os/Bundle;Landroid/os/UserHandle;)Landroid/app/Instrumentation$ActivityResult;
 Landroid/app/IntentService;->mServiceHandler:Landroid/app/IntentService$ServiceHandler;
+Landroid/app/IProcessObserver$Stub;-><init>()V
 Landroid/app/ISearchManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/ISearchManager;
 Landroid/app/ISearchManager$Stub$Proxy;->getGlobalSearchActivity()Landroid/content/ComponentName;
 Landroid/app/ISearchManager$Stub$Proxy;->getWebSearchActivity()Landroid/content/ComponentName;
+Landroid/app/IServiceConnection$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IServiceConnection;
+Landroid/app/IStopUserCallback;->userStopped(I)V
 Landroid/app/IUiModeManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/app/IWallpaperManager;->getWallpaper(Ljava/lang/String;Landroid/app/IWallpaperManagerCallback;ILandroid/os/Bundle;I)Landroid/os/ParcelFileDescriptor;
 Landroid/app/job/IJobScheduler$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/job/IJobScheduler;
@@ -287,16 +316,21 @@
 Landroid/app/LoadedApk;->rewriteRValues(Ljava/lang/ClassLoader;Ljava/lang/String;I)V
 Landroid/app/LocalActivityManager;->mActivities:Ljava/util/Map;
 Landroid/app/LocalActivityManager;->mActivityArray:Ljava/util/ArrayList;
+Landroid/app/LocalActivityManager;->mParent:Landroid/app/Activity;
+Landroid/app/LocalActivityManager;->mResumed:Landroid/app/LocalActivityManager$LocalActivityRecord;
+Landroid/app/LocalActivityManager;->mSingleMode:Z
 Landroid/app/NativeActivity;->hideIme(I)V
 Landroid/app/NativeActivity;->setWindowFlags(II)V
 Landroid/app/NativeActivity;->setWindowFormat(I)V
 Landroid/app/NativeActivity;->showIme(I)V
 Landroid/app/Notification$Builder;->mActions:Ljava/util/ArrayList;
+Landroid/app/Notification$Builder;->makePublicContentView()Landroid/widget/RemoteViews;
 Landroid/app/Notification$Builder;->setChannel(Ljava/lang/String;)Landroid/app/Notification$Builder;
 Landroid/app/Notification;->isGroupSummary()Z
 Landroid/app/NotificationManager;->getService()Landroid/app/INotificationManager;
 Landroid/app/NotificationManager;->notifyAsUser(Ljava/lang/String;ILandroid/app/Notification;Landroid/os/UserHandle;)V
 Landroid/app/NotificationManager;->sService:Landroid/app/INotificationManager;
+Landroid/app/Notification;->mChannelId:Ljava/lang/String;
 Landroid/app/Notification;->mGroupKey:Ljava/lang/String;
 Landroid/app/Notification;->mLargeIcon:Landroid/graphics/drawable/Icon;
 Landroid/app/Notification;->mSmallIcon:Landroid/graphics/drawable/Icon;
@@ -309,6 +343,7 @@
 Landroid/app/ProgressDialog;->mProgressNumber:Landroid/widget/TextView;
 Landroid/app/QueuedWork;->addFinisher(Ljava/lang/Runnable;)V
 Landroid/app/QueuedWork;->removeFinisher(Ljava/lang/Runnable;)V
+Landroid/app/QueuedWork;->sFinishers:Ljava/util/LinkedList;
 Landroid/app/ResourcesManager;->appendLibAssetForMainAssetPath(Ljava/lang/String;Ljava/lang/String;)V
 Landroid/app/ResourcesManager;->getInstance()Landroid/app/ResourcesManager;
 Landroid/app/ResourcesManager;->mActivityResourceReferences:Ljava/util/WeakHashMap;
@@ -322,7 +357,9 @@
 Landroid/app/Service;->mThread:Landroid/app/ActivityThread;
 Landroid/app/Service;->mToken:Landroid/os/IBinder;
 Landroid/app/Service;->setForeground(Z)V
+Landroid/app/SharedPreferencesImpl;-><init>(Ljava/io/File;I)V
 Landroid/app/SharedPreferencesImpl;->mFile:Ljava/io/File;
+Landroid/app/SharedPreferencesImpl;->startReloadIfChangedUnexpectedly()V
 Landroid/app/StatusBarManager;->collapsePanels()V
 Landroid/app/StatusBarManager;->disable(I)V
 Landroid/app/StatusBarManager;->expandNotificationsPanel()V
@@ -429,6 +466,7 @@
 Landroid/content/IContentService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/content/Intent;->ACTION_ALARM_CHANGED:Ljava/lang/String;
 Landroid/content/IntentFilter;->mActions:Ljava/util/ArrayList;
+Landroid/content/Intent;->mExtras:Landroid/os/Bundle;
 Landroid/content/Intent;->putExtra(Ljava/lang/String;Landroid/os/IBinder;)Landroid/content/Intent;
 Landroid/content/pm/ActivityInfo;->resizeMode:I
 Landroid/content/pm/ApplicationInfo;->enabledSetting:I
@@ -439,18 +477,33 @@
 Landroid/content/pm/ApplicationInfo;->privateFlags:I
 Landroid/content/pm/ApplicationInfo;->scanPublicSourceDir:Ljava/lang/String;
 Landroid/content/pm/ApplicationInfo;->scanSourceDir:Ljava/lang/String;
+Landroid/content/pm/ApplicationInfo;->secondaryCpuAbi:Ljava/lang/String;
 Landroid/content/pm/ApplicationInfo;->secondaryNativeLibraryDir:Ljava/lang/String;
 Landroid/content/pm/ComponentInfo;->getComponentName()Landroid/content/ComponentName;
+Landroid/content/pm/IPackageDataObserver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageDataObserver;
+Landroid/content/pm/IPackageManager;->addPermissionAsync(Landroid/content/pm/PermissionInfo;)Z
+Landroid/content/pm/IPackageManager;->addPermission(Landroid/content/pm/PermissionInfo;)Z
+Landroid/content/pm/IPackageManager;->getComponentEnabledSetting(Landroid/content/ComponentName;I)I
+Landroid/content/pm/IPackageManager;->getInstalledPackages(II)Landroid/content/pm/ParceledListSlice;
+Landroid/content/pm/IPackageManager;->getInstallerPackageName(Ljava/lang/String;)Ljava/lang/String;
 Landroid/content/pm/IPackageManager;->getInstallLocation()I
 Landroid/content/pm/IPackageManager;->getLastChosenActivity(Landroid/content/Intent;Ljava/lang/String;I)Landroid/content/pm/ResolveInfo;
+Landroid/content/pm/IPackageManager;->getProviderInfo(Landroid/content/ComponentName;II)Landroid/content/pm/ProviderInfo;
+Landroid/content/pm/IPackageManager;->getReceiverInfo(Landroid/content/ComponentName;II)Landroid/content/pm/ActivityInfo;
+Landroid/content/pm/IPackageManager;->getServiceInfo(Landroid/content/ComponentName;II)Landroid/content/pm/ServiceInfo;
 Landroid/content/pm/IPackageManager;->setApplicationEnabledSetting(Ljava/lang/String;IIILjava/lang/String;)V
 Landroid/content/pm/IPackageManager;->setComponentEnabledSetting(Landroid/content/ComponentName;III)V
+Landroid/content/pm/IPackageManager;->setInstallerPackageName(Ljava/lang/String;Ljava/lang/String;)V
 Landroid/content/pm/IPackageManager;->setLastChosenActivity(Landroid/content/Intent;Ljava/lang/String;ILandroid/content/IntentFilter;ILandroid/content/ComponentName;)V
 Landroid/content/pm/IPackageManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageManager;
+Landroid/content/pm/IPackageManager$Stub$Proxy;->getInstalledPackages(II)Landroid/content/pm/ParceledListSlice;
 Landroid/content/pm/IPackageManager$Stub$Proxy;->getPackageInfo(Ljava/lang/String;II)Landroid/content/pm/PackageInfo;
 Landroid/content/pm/IPackageManager$Stub$Proxy;->getPackagesForUid(I)[Ljava/lang/String;
 Landroid/content/pm/IPackageManager$Stub$Proxy;->getSystemSharedLibraryNames()[Ljava/lang/String;
+Landroid/content/pm/IPackageMoveObserver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageMoveObserver;
+Landroid/content/pm/IPackageMoveObserver$Stub;-><init>()V
 Landroid/content/pm/IPackageStatsObserver$Stub;-><init>()V
+Landroid/content/pm/IShortcutService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/content/pm/LauncherActivityInfo;->mActivityInfo:Landroid/content/pm/ActivityInfo;
 Landroid/content/pm/LauncherApps;->mPm:Landroid/content/pm/PackageManager;
 Landroid/content/pm/LauncherApps;->startShortcut(Ljava/lang/String;Ljava/lang/String;Landroid/graphics/Rect;Landroid/os/Bundle;I)V
@@ -475,14 +528,29 @@
 Landroid/content/pm/PackageParser$Component;->className:Ljava/lang/String;
 Landroid/content/pm/PackageParser$Component;->getComponentName()Landroid/content/ComponentName;
 Landroid/content/pm/PackageParser$Component;->intents:Ljava/util/ArrayList;
+Landroid/content/pm/PackageParser;->generateActivityInfo(Landroid/content/pm/PackageParser$Activity;ILandroid/content/pm/PackageUserState;I)Landroid/content/pm/ActivityInfo;
 Landroid/content/pm/PackageParser;->generatePackageInfo(Landroid/content/pm/PackageParser$Package;[IIJJLjava/util/Set;Landroid/content/pm/PackageUserState;I)Landroid/content/pm/PackageInfo;
 Landroid/content/pm/PackageParser;->generatePackageInfo(Landroid/content/pm/PackageParser$Package;[IIJJLjava/util/Set;Landroid/content/pm/PackageUserState;)Landroid/content/pm/PackageInfo;
+Landroid/content/pm/PackageParser;->generateProviderInfo(Landroid/content/pm/PackageParser$Provider;ILandroid/content/pm/PackageUserState;I)Landroid/content/pm/ProviderInfo;
+Landroid/content/pm/PackageParser;->generateServiceInfo(Landroid/content/pm/PackageParser$Service;ILandroid/content/pm/PackageUserState;I)Landroid/content/pm/ServiceInfo;
 Landroid/content/pm/PackageParser;-><init>()V
+Landroid/content/pm/PackageParser$Instrumentation;->info:Landroid/content/pm/InstrumentationInfo;
+Landroid/content/pm/PackageParser$IntentInfo;->banner:I
+Landroid/content/pm/PackageParser$IntentInfo;->hasDefault:Z
+Landroid/content/pm/PackageParser$IntentInfo;->icon:I
+Landroid/content/pm/PackageParser$IntentInfo;-><init>()V
+Landroid/content/pm/PackageParser$IntentInfo;->labelRes:I
+Landroid/content/pm/PackageParser$IntentInfo;->logo:I
+Landroid/content/pm/PackageParser$IntentInfo;->nonLocalizedLabel:Ljava/lang/CharSequence;
 Landroid/content/pm/PackageParser$Package;->activities:Ljava/util/ArrayList;
 Landroid/content/pm/PackageParser$Package;->applicationInfo:Landroid/content/pm/ApplicationInfo;
+Landroid/content/pm/PackageParser$Package;->instrumentation:Ljava/util/ArrayList;
+Landroid/content/pm/PackageParser$Package;->mAppMetaData:Landroid/os/Bundle;
 Landroid/content/pm/PackageParser$Package;->mVersionCode:I
 Landroid/content/pm/PackageParser$Package;->mVersionName:Ljava/lang/String;
 Landroid/content/pm/PackageParser$Package;->packageName:Ljava/lang/String;
+Landroid/content/pm/PackageParser$Package;->permissionGroups:Ljava/util/ArrayList;
+Landroid/content/pm/PackageParser$Package;->permissions:Ljava/util/ArrayList;
 Landroid/content/pm/PackageParser$Package;->providers:Ljava/util/ArrayList;
 Landroid/content/pm/PackageParser$Package;->receivers:Ljava/util/ArrayList;
 Landroid/content/pm/PackageParser$Package;->requestedPermissions:Ljava/util/ArrayList;
@@ -493,6 +561,7 @@
 Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;IZ)Landroid/content/pm/PackageParser$Package;
 Landroid/content/pm/PackageParser$Provider;->info:Landroid/content/pm/ProviderInfo;
 Landroid/content/pm/PackageParser$ProviderIntentInfo;->provider:Landroid/content/pm/PackageParser$Provider;
+Landroid/content/pm/PackageParser$Service;->info:Landroid/content/pm/ServiceInfo;
 Landroid/content/pm/PackageParser$ServiceIntentInfo;->service:Landroid/content/pm/PackageParser$Service;
 Landroid/content/pm/PackageUserState;-><init>()V
 Landroid/content/pm/ParceledListSlice;-><init>(Ljava/util/List;)V
@@ -531,14 +600,18 @@
 Landroid/content/res/CompatibilityInfo;->applicationScale:F
 Landroid/content/res/CompatibilityInfo;->DEFAULT_COMPATIBILITY_INFO:Landroid/content/res/CompatibilityInfo;
 Landroid/content/res/DrawableCache;->getInstance(JLandroid/content/res/Resources;Landroid/content/res/Resources$Theme;)Landroid/graphics/drawable/Drawable;
+Landroid/content/res/DrawableCache;-><init>()V
 Landroid/content/res/ObbInfo;->salt:[B
 Landroid/content/res/Resources;->getCompatibilityInfo()Landroid/content/res/CompatibilityInfo;
+Landroid/content/res/ResourcesImpl;->getAssets()Landroid/content/res/AssetManager;
 Landroid/content/res/ResourcesImpl;->mAccessLock:Ljava/lang/Object;
+Landroid/content/res/ResourcesImpl;->mAnimatorCache:Landroid/content/res/ConfigurationBoundResourceCache;
 Landroid/content/res/ResourcesImpl;->mAssets:Landroid/content/res/AssetManager;
 Landroid/content/res/ResourcesImpl;->mColorDrawableCache:Landroid/content/res/DrawableCache;
 Landroid/content/res/ResourcesImpl;->mConfiguration:Landroid/content/res/Configuration;
 Landroid/content/res/ResourcesImpl;->mDrawableCache:Landroid/content/res/DrawableCache;
 Landroid/content/res/ResourcesImpl;->mPreloading:Z
+Landroid/content/res/ResourcesImpl;->mStateListAnimatorCache:Landroid/content/res/ConfigurationBoundResourceCache;
 Landroid/content/res/ResourcesImpl;->sPreloadedColorDrawables:Landroid/util/LongSparseArray;
 Landroid/content/res/ResourcesImpl;->sPreloadedComplexColors:Landroid/util/LongSparseArray;
 Landroid/content/res/ResourcesImpl;->sPreloadedDrawables:[Landroid/util/LongSparseArray;
@@ -554,6 +627,7 @@
 Landroid/content/res/Resources;->setCompatibilityInfo(Landroid/content/res/CompatibilityInfo;)V
 Landroid/content/res/Resources;->updateSystemConfiguration(Landroid/content/res/Configuration;Landroid/util/DisplayMetrics;Landroid/content/res/CompatibilityInfo;)V
 Landroid/content/res/StringBlock;-><init>(JZ)V
+Landroid/content/res/ThemedResourceCache;->onConfigurationChange(I)V
 Landroid/content/res/TypedArray;->extractThemeAttrs()[I
 Landroid/content/res/TypedArray;->getNonConfigurationString(II)Ljava/lang/String;
 Landroid/content/res/TypedArray;->getValueAt(ILandroid/util/TypedValue;)Z
@@ -572,7 +646,10 @@
 Landroid/content/res/XmlBlock$Parser;->mBlock:Landroid/content/res/XmlBlock;
 Landroid/content/res/XmlBlock$Parser;->mParseState:J
 Landroid/content/SearchRecentSuggestionsProvider;->mSuggestionProjection:[Ljava/lang/String;
+Landroid/content/SyncContext;->setStatusText(Ljava/lang/String;)V
 Landroid/content/SyncStatusInfo;->lastSuccessTime:J
+Landroid/content/UriMatcher;->mChildren:Ljava/util/ArrayList;
+Landroid/content/UriMatcher;->mText:Ljava/lang/String;
 Landroid/database/AbstractCursor;->mExtras:Landroid/os/Bundle;
 Landroid/database/AbstractCursor;->mNotifyUri:Landroid/net/Uri;
 Landroid/database/AbstractCursor;->mRowIdColumnIndex:I
@@ -591,6 +668,7 @@
 Landroid/database/sqlite/SQLiteDebug$PagerStats;->pageCacheOverflow:I
 Landroid/database/sqlite/SQLiteOpenHelper;->mName:Ljava/lang/String;
 Landroid/ddm/DdmHandleAppName;->getAppName()Ljava/lang/String;
+Landroid/graphics/AvoidXfermode$Mode;->AVOID:Landroid/graphics/AvoidXfermode$Mode;
 Landroid/graphics/AvoidXfermode$Mode;->TARGET:Landroid/graphics/AvoidXfermode$Mode;
 Landroid/graphics/BaseCanvas;->mNativeCanvasWrapper:J
 Landroid/graphics/Bitmap$Config;->nativeInt:I
@@ -612,10 +690,10 @@
 Landroid/graphics/Canvas;-><init>(J)V
 Landroid/graphics/Canvas;->release()V
 Landroid/graphics/Canvas;->save(I)I
-Landroid/graphics/Canvas;->saveLayer(Landroid/graphics/RectF;Landroid/graphics/Paint;I)I
-Landroid/graphics/Canvas;->saveLayer(FFFFLandroid/graphics/Paint;I)I
-Landroid/graphics/Canvas;->saveLayerAlpha(Landroid/graphics/RectF;II)I
 Landroid/graphics/Canvas;->saveLayerAlpha(FFFFII)I
+Landroid/graphics/Canvas;->saveLayerAlpha(Landroid/graphics/RectF;II)I
+Landroid/graphics/Canvas;->saveLayer(FFFFLandroid/graphics/Paint;I)I
+Landroid/graphics/Canvas;->saveLayer(Landroid/graphics/RectF;Landroid/graphics/Paint;I)I
 Landroid/graphics/ColorMatrixColorFilter;->setColorMatrix(Landroid/graphics/ColorMatrix;)V
 Landroid/graphics/drawable/AnimatedImageDrawable;->onAnimationEnd()V
 Landroid/graphics/drawable/AnimatedStateListDrawable$AnimatedStateListState;->mStateIds:Landroid/util/SparseIntArray;
@@ -628,6 +706,7 @@
 Landroid/graphics/drawable/BitmapDrawable;->getTintMode()Landroid/graphics/PorterDuff$Mode;
 Landroid/graphics/drawable/BitmapDrawable;->mTargetDensity:I
 Landroid/graphics/drawable/BitmapDrawable;->setBitmap(Landroid/graphics/Bitmap;)V
+Landroid/graphics/drawable/ColorDrawable$ColorState;->mUseColor:I
 Landroid/graphics/drawable/DrawableContainer$DrawableContainerState;->mConstantPadding:Landroid/graphics/Rect;
 Landroid/graphics/drawable/DrawableContainer;->getOpticalInsets()Landroid/graphics/Insets;
 Landroid/graphics/drawable/DrawableContainer;->mDrawableContainerState:Landroid/graphics/drawable/DrawableContainer$DrawableContainerState;
@@ -771,6 +850,7 @@
 Landroid/hardware/Camera;->postEventFromNative(Ljava/lang/Object;IIILjava/lang/Object;)V
 Landroid/hardware/display/WifiDisplayStatus;->mActiveDisplay:Landroid/hardware/display/WifiDisplay;
 Landroid/hardware/display/WifiDisplayStatus;->mDisplays:[Landroid/hardware/display/WifiDisplay;
+Landroid/hardware/fingerprint/IFingerprintService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/hardware/HardwareBuffer;-><init>(J)V
 Landroid/hardware/HardwareBuffer;->mNativeObject:J
 Landroid/hardware/input/IInputManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/input/IInputManager;
@@ -849,6 +929,9 @@
 Landroid/icu/text/UFormat;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
 Landroid/icu/util/Calendar;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
 Landroid/inputmethodservice/InputMethodService;->mExtractEditText:Landroid/inputmethodservice/ExtractEditText;
+Landroid/inputmethodservice/InputMethodService;->mRootView:Landroid/view/View;
+Landroid/inputmethodservice/InputMethodService;->mSettingsObserver:Landroid/inputmethodservice/InputMethodService$SettingsObserver;
+Landroid/inputmethodservice/InputMethodService$SettingsObserver;->shouldShowImeWithHardKeyboard()Z
 Landroid/location/CountryDetector;->detectCountry()Landroid/location/Country;
 Landroid/location/Country;->getCountryIso()Ljava/lang/String;
 Landroid/location/Country;->getSource()I
@@ -945,11 +1028,14 @@
 Landroid/media/AudioTrack;->mStreamType:I
 Landroid/media/AudioTrack;->native_release()V
 Landroid/media/AudioTrack;->postEventFromNative(Ljava/lang/Object;IIILjava/lang/Object;)V
+Landroid/media/ExifInterface;->getDateTime()J
 Landroid/media/IAudioService;->getStreamMaxVolume(I)I
 Landroid/media/IAudioService;->getStreamVolume(I)I
 Landroid/media/IAudioService;->setStreamVolume(IIILjava/lang/String;)V
 Landroid/media/IAudioService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IAudioService;
 Landroid/media/IAudioService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Landroid/media/IMediaScannerService;->scanFile(Ljava/lang/String;Ljava/lang/String;)V
+Landroid/media/IMediaScannerService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IMediaScannerService;
 Landroid/media/IRemoteDisplayCallback;->onStateChanged(Landroid/media/RemoteDisplayState;)V
 Landroid/media/IVolumeController$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IVolumeController;
 Landroid/media/JetPlayer;->mNativePlayerInJavaObj:J
@@ -1060,11 +1146,16 @@
 Landroid/net/ConnectivityManager;->TYPE_PROXY:I
 Landroid/net/ConnectivityManager;->TYPE_WIFI_P2P:I
 Landroid/net/IConnectivityManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/IConnectivityManager;
+Landroid/net/IConnectivityManager$Stub$Proxy;->getActiveLinkProperties()Landroid/net/LinkProperties;
+Landroid/net/IConnectivityManager$Stub$Proxy;->getActiveNetworkInfo()Landroid/net/NetworkInfo;
+Landroid/net/IConnectivityManager$Stub$Proxy;->getAllNetworkInfo()[Landroid/net/NetworkInfo;
 Landroid/net/IConnectivityManager$Stub$Proxy;->getAllNetworks()[Landroid/net/Network;
 Landroid/net/IConnectivityManager$Stub$Proxy;->getTetherableIfaces()[Ljava/lang/String;
 Landroid/net/IConnectivityManager$Stub$Proxy;->getTetherableUsbRegexs()[Ljava/lang/String;
+Landroid/net/IConnectivityManager$Stub$Proxy;->getTetheredIfaces()[Ljava/lang/String;
 Landroid/net/IConnectivityManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/net/INetworkStatsService$Stub$Proxy;->getMobileIfaces()[Ljava/lang/String;
+Landroid/net/INetworkStatsService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/net/IpConfiguration;->httpProxy:Landroid/net/ProxyInfo;
 Landroid/net/LinkProperties;->setHttpProxy(Landroid/net/ProxyInfo;)V
 Landroid/net/LocalSocketImpl;->inboundFileDescriptors:[Ljava/io/FileDescriptor;
@@ -1088,6 +1179,7 @@
 Landroid/net/NetworkStats;->txPackets:[J
 Landroid/net/NetworkStats;->uid:[I
 Landroid/net/NetworkTemplate;->buildTemplateWifi()Landroid/net/NetworkTemplate;
+Landroid/net/Proxy;->getProxy(Landroid/content/Context;Ljava/lang/String;)Ljava/net/Proxy;
 Landroid/net/ProxyInfo;-><init>(Ljava/lang/String;ILjava/lang/String;)V
 Landroid/net/SntpClient;-><init>()V
 Landroid/net/SSLCertificateSocketFactory;->castToOpenSSLSocket(Ljava/net/Socket;)Lcom/android/org/conscrypt/OpenSSLSocketImpl;
@@ -1114,6 +1206,7 @@
 Landroid/net/SSLCertificateSocketFactory;->TAG:Ljava/lang/String;
 Landroid/net/SSLCertificateSocketFactory;->verifyHostname(Ljava/net/Socket;Ljava/lang/String;)V
 Landroid/net/SSLSessionCache;->mSessionCache:Lcom/android/org/conscrypt/SSLClientSessionCache;
+Landroid/net/TrafficStats;->getMobileIfaces()[Ljava/lang/String;
 Landroid/net/TrafficStats;->getRxBytes(Ljava/lang/String;)J
 Landroid/net/TrafficStats;->getStatsService()Landroid/net/INetworkStatsService;
 Landroid/net/TrafficStats;->getTxBytes(Ljava/lang/String;)J
@@ -1122,12 +1215,12 @@
 Landroid/net/wifi/IWifiManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/net/wifi/p2p/WifiP2pGroup;->getNetworkId()I
 Landroid/net/wifi/p2p/WifiP2pGroupList;->getGroupList()Ljava/util/Collection;
+Landroid/net/wifi/p2p/WifiP2pManager$Channel;->mAsyncChannel:Lcom/android/internal/util/AsyncChannel;
+Landroid/net/wifi/p2p/WifiP2pManager$Channel;->putListener(Ljava/lang/Object;)I
 Landroid/net/wifi/p2p/WifiP2pManager;->deletePersistentGroup(Landroid/net/wifi/p2p/WifiP2pManager$Channel;ILandroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V
 Landroid/net/wifi/p2p/WifiP2pManager;->requestPersistentGroupInfo(Landroid/net/wifi/p2p/WifiP2pManager$Channel;Landroid/net/wifi/p2p/WifiP2pManager$PersistentGroupInfoListener;)V
 Landroid/net/wifi/p2p/WifiP2pManager;->setDeviceName(Landroid/net/wifi/p2p/WifiP2pManager$Channel;Ljava/lang/String;Landroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V
 Landroid/net/wifi/p2p/WifiP2pManager;->setWifiP2pChannels(Landroid/net/wifi/p2p/WifiP2pManager$Channel;IILandroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V
-Landroid/net/wifi/p2p/WifiP2pManager$Channel;->mAsyncChannel:Lcom/android/internal/util/AsyncChannel;
-Landroid/net/wifi/p2p/WifiP2pManager$Channel;->putListener(Ljava/lang/Object;)I
 Landroid/net/wifi/ScanResult;->anqpDomainId:I
 Landroid/net/wifi/ScanResult;->anqpLines:Ljava/util/List;
 Landroid/net/wifi/ScanResult;->distanceCm:I
@@ -1157,10 +1250,12 @@
 Landroid/net/wifi/WifiConfiguration;->apBand:I
 Landroid/net/wifi/WifiConfiguration;->apChannel:I
 Landroid/net/wifi/WifiConfiguration;->defaultGwMacAddress:Ljava/lang/String;
+Landroid/net/wifi/WifiConfiguration;->lastConnectUid:I
 Landroid/net/wifi/WifiConfiguration;->mIpConfiguration:Landroid/net/IpConfiguration;
 Landroid/net/wifi/WifiConfiguration;->validatedInternetAccess:Z
 Landroid/net/wifi/WifiEnterpriseConfig;->getCaCertificateAlias()Ljava/lang/String;
 Landroid/net/wifi/WifiEnterpriseConfig;->getClientCertificateAlias()Ljava/lang/String;
+Landroid/net/wifi/WifiInfo;->DEFAULT_MAC_ADDRESS:Ljava/lang/String;
 Landroid/net/wifi/WifiInfo;->getMeteredHint()Z
 Landroid/net/wifi/WifiInfo;->mMacAddress:Ljava/lang/String;
 Landroid/net/wifi/WifiInfo;->removeDoubleQuotes(Ljava/lang/String;)Ljava/lang/String;
@@ -1182,17 +1277,30 @@
 Landroid/os/AsyncTask;->mWorker:Landroid/os/AsyncTask$WorkerRunnable;
 Landroid/os/AsyncTask;->sDefaultExecutor:Ljava/util/concurrent/Executor;
 Landroid/os/AsyncTask;->setDefaultExecutor(Ljava/util/concurrent/Executor;)V
+Landroid/os/BatteryStats$Counter;->getCountLocked(I)I
 Landroid/os/BatteryStats;->getUidStats()Landroid/util/SparseArray;
 Landroid/os/BatteryStats$HistoryItem;->states2:I
 Landroid/os/BatteryStats;->NUM_DATA_CONNECTION_TYPES:I
 Landroid/os/BatteryStats;->startIteratingHistoryLocked()Z
 Landroid/os/BatteryStats$Timer;->getTotalTimeLocked(JI)J
+Landroid/os/BatteryStats$Uid;->getAudioTurnedOnTimer()Landroid/os/BatteryStats$Timer;
 Landroid/os/BatteryStats$Uid;->getFullWifiLockTime(JI)J
+Landroid/os/BatteryStats$Uid;->getPackageStats()Landroid/util/ArrayMap;
 Landroid/os/BatteryStats$Uid;->getProcessStats()Landroid/util/ArrayMap;
 Landroid/os/BatteryStats$Uid;->getSensorStats()Landroid/util/SparseArray;
 Landroid/os/BatteryStats$Uid;->getUid()I
+Landroid/os/BatteryStats$Uid;->getVideoTurnedOnTimer()Landroid/os/BatteryStats$Timer;
 Landroid/os/BatteryStats$Uid;->getWifiMulticastTime(JI)J
 Landroid/os/BatteryStats$Uid;->getWifiScanTime(JI)J
+Landroid/os/BatteryStats$Uid$Pkg;->getServiceStats()Landroid/util/ArrayMap;
+Landroid/os/BatteryStats$Uid$Pkg;->getWakeupAlarmStats()Landroid/util/ArrayMap;
+Landroid/os/BatteryStats$Uid$Pkg$Serv;->getLaunches(I)I
+Landroid/os/BatteryStats$Uid$Pkg$Serv;->getStartTime(JI)J
+Landroid/os/BatteryStats$Uid$Proc;->countExcessivePowers()I
+Landroid/os/BatteryStats$Uid$Proc$ExcessivePower;->overTime:J
+Landroid/os/BatteryStats$Uid$Proc$ExcessivePower;->type:I
+Landroid/os/BatteryStats$Uid$Proc$ExcessivePower;->usedTime:J
+Landroid/os/BatteryStats$Uid$Proc;->getExcessivePower(I)Landroid/os/BatteryStats$Uid$Proc$ExcessivePower;
 Landroid/os/BatteryStats$Uid$Proc;->getForegroundTime(I)J
 Landroid/os/BatteryStats$Uid$Proc;->getSystemTime(I)J
 Landroid/os/BatteryStats$Uid$Proc;->getUserTime(I)J
@@ -1239,6 +1347,7 @@
 Landroid/os/Debug$MemoryInfo;->otherSwappedOutPss:I
 Landroid/os/Environment;->buildExternalStorageAppDataDirs(Ljava/lang/String;)[Ljava/io/File;
 Landroid/os/Environment;->getVendorDirectory()Ljava/io/File;
+Landroid/os/Environment;->maybeTranslateEmulatedPathToInternal(Ljava/io/File;)Ljava/io/File;
 Landroid/os/FileObserver$ObserverThread;->onEvent(IILjava/lang/String;)V
 Landroid/os/FileUtils;->checksumCrc32(Ljava/io/File;)J
 Landroid/os/FileUtils;->copyFile(Ljava/io/File;Ljava/io/File;)Z
@@ -1250,6 +1359,7 @@
 Landroid/os/FileUtils;->setPermissions(Ljava/lang/String;III)I
 Landroid/os/FileUtils;->stringToFile(Ljava/io/File;Ljava/lang/String;)V
 Landroid/os/FileUtils;->stringToFile(Ljava/lang/String;Ljava/lang/String;)V
+Landroid/os/FileUtils;->sync(Ljava/io/FileOutputStream;)Z
 Landroid/os/Handler;->getIMessenger()Landroid/os/IMessenger;
 Landroid/os/Handler;->hasCallbacks(Ljava/lang/Runnable;)Z
 Landroid/os/Handler;-><init>(Z)V
@@ -1264,6 +1374,7 @@
 Landroid/os/IPowerManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/os/IPowerManager$Stub$Proxy;->isLightDeviceIdleMode()Z
 Landroid/os/IPowerManager;->userActivity(JII)V
+Landroid/os/IServiceManager;->checkService(Ljava/lang/String;)Landroid/os/IBinder;
 Landroid/os/IServiceManager;->getService(Ljava/lang/String;)Landroid/os/IBinder;
 Landroid/os/IUserManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/os/Looper;->mQueue:Landroid/os/MessageQueue;
@@ -1307,6 +1418,7 @@
 Landroid/os/Process;->isIsolated(I)Z
 Landroid/os/Process;->readProcFile(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z
 Landroid/os/Process;->readProcLines(Ljava/lang/String;[Ljava/lang/String;[J)V
+Landroid/os/Process;->setArgV0(Ljava/lang/String;)V
 Landroid/os/SELinux;->isSELinuxEnabled()Z
 Landroid/os/SELinux;->isSELinuxEnforced()Z
 Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;)V
@@ -1468,13 +1580,16 @@
 Landroid/print/PrinterId;->getServiceName()Landroid/content/ComponentName;
 Landroid/print/PrintJobInfo;->getAdvancedOptions()Landroid/os/Bundle;
 Landroid/print/PrintJobInfo;->getDocumentInfo()Landroid/print/PrintDocumentInfo;
+Landroid/provider/Browser$BookmarkColumns;->DATE:Ljava/lang/String;
 Landroid/provider/Browser;->BOOKMARKS_URI:Landroid/net/Uri;
 Landroid/provider/Browser;->canClearHistory(Landroid/content/ContentResolver;)Z
 Landroid/provider/Browser;->clearHistory(Landroid/content/ContentResolver;)V
 Landroid/provider/Browser;->clearSearches(Landroid/content/ContentResolver;)V
 Landroid/provider/Browser;->deleteFromHistory(Landroid/content/ContentResolver;Ljava/lang/String;)V
 Landroid/provider/Browser;->getVisitedHistory(Landroid/content/ContentResolver;)[Ljava/lang/String;
+Landroid/provider/Browser;->SEARCHES_URI:Landroid/net/Uri;
 Landroid/provider/Browser;->sendString(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)V
+Landroid/provider/Browser;->updateVisitedHistory(Landroid/content/ContentResolver;Ljava/lang/String;Z)V
 Landroid/provider/CalendarContract$CalendarAlerts;->findNextAlarmTime(Landroid/content/ContentResolver;J)J
 Landroid/provider/CalendarContract$CalendarAlerts;->rescheduleMissedAlarms(Landroid/content/ContentResolver;Landroid/content/Context;Landroid/app/AlarmManager;)V
 Landroid/provider/Settings$ContentProviderHolder;->mContentProvider:Landroid/content/IContentProvider;
@@ -1702,6 +1817,7 @@
 Landroid/R$styleable;->Window:[I
 Landroid/R$styleable;->Window_windowBackground:I
 Landroid/R$styleable;->Window_windowFrame:I
+Landroid/security/keystore/AndroidKeyStoreProvider;->getKeyStoreOperationHandle(Ljava/lang/Object;)J
 Landroid/security/KeyStore;->getInstance()Landroid/security/KeyStore;
 Landroid/security/keystore/KeychainProtectionParams;->clearSecret()V
 Landroid/security/keystore/KeychainProtectionParams;->getKeyDerivationParams()Landroid/security/keystore/KeyDerivationParams;
@@ -1850,6 +1966,7 @@
 Landroid/telephony/SubscriptionManager;->getActiveSubscriptionIdList()[I
 Landroid/telephony/SubscriptionManager;->getAllSubscriptionInfoCount()I
 Landroid/telephony/SubscriptionManager;->getAllSubscriptionInfoList()Ljava/util/List;
+Landroid/telephony/SubscriptionManager;->getDefaultDataPhoneId()I
 Landroid/telephony/SubscriptionManager;->getDefaultDataSubscriptionInfo()Landroid/telephony/SubscriptionInfo;
 Landroid/telephony/SubscriptionManager;->getDefaultSmsPhoneId()I
 Landroid/telephony/SubscriptionManager;->getDefaultVoiceSubscriptionInfo()Landroid/telephony/SubscriptionInfo;
@@ -1889,6 +2006,7 @@
 Landroid/telephony/TelephonyManager;->isMultiSimEnabled()Z
 Landroid/telephony/TelephonyManager;->isNetworkRoaming(I)Z
 Landroid/telephony/TelephonyManager;->isVolteAvailable()Z
+Landroid/telephony/TelephonyManager;->mSubscriptionManager:Landroid/telephony/SubscriptionManager;
 Landroid/text/AndroidBidi;->bidi(I[C[B)I
 Landroid/text/DynamicLayout;-><init>(Ljava/lang/CharSequence;Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout$Alignment;Landroid/text/TextDirectionHeuristic;FFZIIILandroid/text/TextUtils$TruncateAt;I)V
 Landroid/text/DynamicLayout;->sStaticLayout:Landroid/text/StaticLayout;
@@ -1945,6 +2063,7 @@
 Landroid/text/StaticLayout;->mColumns:I
 Landroid/text/StaticLayout;->mLineCount:I
 Landroid/text/StaticLayout;->mLines:[I
+Landroid/text/StaticLayout;->mMaximumVisibleLineCount:I
 Landroid/text/TextLine;->mCharacterStyleSpanSet:Landroid/text/SpanSet;
 Landroid/text/TextLine;->mMetricAffectingSpanSpanSet:Landroid/text/SpanSet;
 Landroid/text/TextLine;->mReplacementSpanSpanSet:Landroid/text/SpanSet;
@@ -1976,6 +2095,8 @@
 Landroid/util/Pools$SynchronizedPool;-><init>(I)V
 Landroid/util/Rational;->mDenominator:I
 Landroid/util/Rational;->mNumerator:I
+Landroid/util/Singleton;->get()Ljava/lang/Object;
+Landroid/util/Singleton;-><init>()V
 Landroid/util/Singleton;->mInstance:Ljava/lang/Object;
 Landroid/util/Slog;->d(Ljava/lang/String;Ljava/lang/String;)I
 Landroid/util/Slog;->w(Ljava/lang/String;Ljava/lang/String;)I
@@ -1984,6 +2105,7 @@
 Landroid/util/SparseIntArray;->mValues:[I
 Landroid/view/accessibility/AccessibilityManager;->getInstance(Landroid/content/Context;)Landroid/view/accessibility/AccessibilityManager;
 Landroid/view/accessibility/AccessibilityManager;->isHighTextContrastEnabled()Z
+Landroid/view/accessibility/AccessibilityManager;->mAccessibilityStateChangeListeners:Landroid/util/ArrayMap;
 Landroid/view/accessibility/AccessibilityManager;->mIsEnabled:Z
 Landroid/view/accessibility/AccessibilityManager;->mIsHighTextContrastEnabled:Z
 Landroid/view/accessibility/AccessibilityManager;->sInstance:Landroid/view/accessibility/AccessibilityManager;
@@ -2033,6 +2155,7 @@
 Landroid/view/inputmethod/InputMethodInfo;->mSubtypes:Landroid/view/inputmethod/InputMethodSubtypeArray;
 Landroid/view/inputmethod/InputMethodManager;->finishInputLocked()V
 Landroid/view/inputmethod/InputMethodManager;->focusIn(Landroid/view/View;)V
+Landroid/view/inputmethod/InputMethodManager;->focusOut(Landroid/view/View;)V
 Landroid/view/inputmethod/InputMethodManager;->getInputMethodWindowVisibleHeight()I
 Landroid/view/inputmethod/InputMethodManager;->mCurId:Ljava/lang/String;
 Landroid/view/inputmethod/InputMethodManager;->mCurRootView:Landroid/view/View;
@@ -2041,6 +2164,7 @@
 Landroid/view/inputmethod/InputMethodManager;->mServedView:Landroid/view/View;
 Landroid/view/inputmethod/InputMethodManager;->mService:Lcom/android/internal/view/IInputMethodManager;
 Landroid/view/inputmethod/InputMethodManager;->notifyUserAction()V
+Landroid/view/inputmethod/InputMethodManager;->peekInstance()Landroid/view/inputmethod/InputMethodManager;
 Landroid/view/inputmethod/InputMethodManager;->showSoftInputUnchecked(ILandroid/os/ResultReceiver;)V
 Landroid/view/inputmethod/InputMethodManager;->sInstance:Landroid/view/inputmethod/InputMethodManager;
 Landroid/view/inputmethod/InputMethodManager;->windowDismissed(Landroid/os/IBinder;)V
@@ -2054,6 +2178,7 @@
 Landroid/view/IWindowManager;->setStrictModeVisualIndicatorPreference(Ljava/lang/String;)V
 Landroid/view/IWindowManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/IWindowManager;
 Landroid/view/IWindowManager$Stub$Proxy;->getBaseDisplayDensity(I)I
+Landroid/view/IWindowManager$Stub$Proxy;->getDockedStackSide()I
 Landroid/view/IWindowManager$Stub$Proxy;->getInitialDisplayDensity(I)I
 Landroid/view/IWindowManager$Stub$Proxy;->hasNavigationBar()Z
 Landroid/view/IWindowManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -2084,6 +2209,7 @@
 Landroid/view/LayoutInflater;->mPrivateFactory:Landroid/view/LayoutInflater$Factory2;
 Landroid/view/LayoutInflater;->sConstructorMap:Ljava/util/HashMap;
 Landroid/view/LayoutInflater;->setPrivateFactory(Landroid/view/LayoutInflater$Factory2;)V
+Landroid/view/MotionEvent;->getPointerIdBits()I
 Landroid/view/MotionEvent;->HISTORY_CURRENT:I
 Landroid/view/MotionEvent;->mNativePtr:J
 Landroid/view/MotionEvent;->nativeGetRawAxisValue(JIII)F
@@ -2091,6 +2217,7 @@
 Landroid/view/MotionEvent$PointerCoords;->mPackedAxisBits:J
 Landroid/view/MotionEvent$PointerCoords;->mPackedAxisValues:[F
 Landroid/view/MotionEvent;->scale(F)V
+Landroid/view/MotionEvent;->split(I)Landroid/view/MotionEvent;
 Landroid/view/PointerIcon;->load(Landroid/content/Context;)Landroid/view/PointerIcon;
 Landroid/view/PointerIcon;->mBitmapFrames:[Landroid/graphics/Bitmap;
 Landroid/view/PointerIcon;->mBitmap:Landroid/graphics/Bitmap;
@@ -2111,6 +2238,8 @@
 Landroid/view/RemoteAnimationTarget;->taskId:I
 Landroid/view/RemoteAnimationTarget;->windowConfiguration:Landroid/app/WindowConfiguration;
 Landroid/view/RenderNodeAnimator;->callOnFinished(Landroid/view/RenderNodeAnimator;)V
+Landroid/view/RenderNode;->discardDisplayList()V
+Landroid/view/RenderNode;->output()V
 Landroid/view/ScaleGestureDetector;->mListener:Landroid/view/ScaleGestureDetector$OnScaleGestureListener;
 Landroid/view/ScaleGestureDetector;->mMinSpan:I
 Landroid/view/SurfaceControl$PhysicalDisplayInfo;->appVsyncOffsetNanos:J
@@ -2145,6 +2274,7 @@
 Landroid/view/textclassifier/TextClassificationManager;->getTextClassifier(I)Landroid/view/textclassifier/TextClassifier;
 Landroid/view/textservice/TextServicesManager;->isSpellCheckerEnabled()Z
 Landroid/view/TextureView;->destroyHardwareLayer()V
+Landroid/view/TextureView;->destroyHardwareResources()V
 Landroid/view/TextureView;->mLayer:Landroid/view/TextureLayer;
 Landroid/view/TextureView;->mNativeWindow:J
 Landroid/view/TextureView;->mSurface:Landroid/graphics/SurfaceTexture;
@@ -2156,6 +2286,7 @@
 Landroid/view/VelocityTracker$Estimator;->yCoeff:[F
 Landroid/view/VelocityTracker;->obtain(Ljava/lang/String;)Landroid/view/VelocityTracker;
 Landroid/view/View;->applyDrawableToTransparentRegion(Landroid/graphics/drawable/Drawable;Landroid/graphics/Region;)V
+Landroid/view/View$AttachInfo;->mContentInsets:Landroid/graphics/Rect;
 Landroid/view/View$AttachInfo;->mDrawingTime:J
 Landroid/view/View$AttachInfo;->mStableInsets:Landroid/graphics/Rect;
 Landroid/view/View;->clearAccessibilityFocus()V
@@ -2174,12 +2305,14 @@
 Landroid/view/View;->fitsSystemWindows()Z
 Landroid/view/View;->getAccessibilityDelegate()Landroid/view/View$AccessibilityDelegate;
 Landroid/view/View;->getBoundsOnScreen(Landroid/graphics/Rect;)V
+Landroid/view/View;->getHorizontalScrollFactor()F
 Landroid/view/View;->getInverseMatrix()Landroid/graphics/Matrix;
 Landroid/view/View;->getListenerInfo()Landroid/view/View$ListenerInfo;
 Landroid/view/View;->getLocationOnScreen()[I
 Landroid/view/View;->getRawTextAlignment()I
 Landroid/view/View;->getRawTextDirection()I
 Landroid/view/View;->getTransitionAlpha()F
+Landroid/view/View;->getVerticalScrollFactor()F
 Landroid/view/View;->getViewRootImpl()Landroid/view/ViewRootImpl;
 Landroid/view/View;->getWindowDisplayFrame(Landroid/graphics/Rect;)V
 Landroid/view/ViewGroup;->dispatchViewAdded(Landroid/view/View;)V
@@ -2194,18 +2327,23 @@
 Landroid/view/ViewGroup;->mFirstTouchTarget:Landroid/view/ViewGroup$TouchTarget;
 Landroid/view/ViewGroup;->mGroupFlags:I
 Landroid/view/ViewGroup;->mOnHierarchyChangeListener:Landroid/view/ViewGroup$OnHierarchyChangeListener;
+Landroid/view/ViewGroup;->mPersistentDrawingCache:I
+Landroid/view/ViewGroup;->offsetChildrenTopAndBottom(I)V
 Landroid/view/ViewGroup;->resetResolvedDrawables()V
 Landroid/view/ViewGroup;->resetResolvedLayoutDirection()V
 Landroid/view/ViewGroup;->resetResolvedPadding()V
 Landroid/view/ViewGroup;->resetResolvedTextAlignment()V
 Landroid/view/ViewGroup;->resetResolvedTextDirection()V
 Landroid/view/ViewGroup;->suppressLayout(Z)V
+Landroid/view/View;->includeForAccessibility()Z
 Landroid/view/View;->initializeScrollbars(Landroid/content/res/TypedArray;)V
 Landroid/view/View;->internalSetPadding(IIII)V
 Landroid/view/View;->isPaddingResolved()Z
 Landroid/view/View;->isVisibleToUser(Landroid/graphics/Rect;)Z
 Landroid/view/View;->isVisibleToUser()Z
+Landroid/view/View$ListenerInfo;-><init>()V
 Landroid/view/View$ListenerInfo;->mOnClickListener:Landroid/view/View$OnClickListener;
+Landroid/view/View$ListenerInfo;->mOnFocusChangeListener:Landroid/view/View$OnFocusChangeListener;
 Landroid/view/View$ListenerInfo;->mOnLongClickListener:Landroid/view/View$OnLongClickListener;
 Landroid/view/View$ListenerInfo;->mOnTouchListener:Landroid/view/View$OnTouchListener;
 Landroid/view/View;->mAccessibilityDelegate:Landroid/view/View$AccessibilityDelegate;
@@ -2218,10 +2356,13 @@
 Landroid/view/View;->mListenerInfo:Landroid/view/View$ListenerInfo;
 Landroid/view/View;->mMinHeight:I
 Landroid/view/View;->mMinWidth:I
+Landroid/view/View;->mPaddingBottom:I
 Landroid/view/View;->mPaddingLeft:I
 Landroid/view/View;->mPaddingRight:I
+Landroid/view/View;->mPaddingTop:I
 Landroid/view/View;->mParent:Landroid/view/ViewParent;
 Landroid/view/View;->mPrivateFlags3:I
+Landroid/view/View;->mPrivateFlags:I
 Landroid/view/View;->mRecreateDisplayList:Z
 Landroid/view/View;->mResources:Landroid/content/res/Resources;
 Landroid/view/View;->mRight:I
@@ -2234,6 +2375,8 @@
 Landroid/view/View;->mUnscaledDrawingCache:Landroid/graphics/Bitmap;
 Landroid/view/View;->mViewFlags:I
 Landroid/view/View;->notifySubtreeAccessibilityStateChangedIfNeeded()V
+Landroid/view/View;->onDrawVerticalScrollBar(Landroid/graphics/Canvas;Landroid/graphics/drawable/Drawable;IIII)V
+Landroid/view/View;->performAccessibilityActionInternal(ILandroid/os/Bundle;)Z
 Landroid/view/View;->recomputePadding()V
 Landroid/view/View;->requestAccessibilityFocus()Z
 Landroid/view/View;->resetDisplayList()V
@@ -2294,7 +2437,10 @@
 Landroid/view/WindowManager$LayoutParams;->userActivityTimeout:J
 Landroid/view/Window;->mAppName:Ljava/lang/String;
 Landroid/view/Window;->mAppToken:Landroid/os/IBinder;
+Landroid/view/Window;->mCallback:Landroid/view/Window$Callback;
+Landroid/view/Window;->mContext:Landroid/content/Context;
 Landroid/view/Window;->mHardwareAccelerated:Z
+Landroid/view/Window;->mWindowStyle:Landroid/content/res/TypedArray;
 Landroid/webkit/IWebViewUpdateService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/webkit/WebResourceResponse;->mImmutable:Z
 Landroid/webkit/WebSyncManager;->mHandler:Landroid/os/Handler;
@@ -2307,6 +2453,7 @@
 Landroid/webkit/WebViewFactory;->getWebViewContextAndSetProvider()Landroid/content/Context;
 Landroid/webkit/WebViewFactory;->sPackageInfo:Landroid/content/pm/PackageInfo;
 Landroid/webkit/WebViewFactory;->sProviderInstance:Landroid/webkit/WebViewFactoryProvider;
+Landroid/webkit/WebView;->getTouchIconUrl()Ljava/lang/String;
 Landroid/webkit/WebView;->getVisibleTitleHeight()I
 Landroid/webkit/WebView;->isPaused()Z
 Landroid/webkit/WebView;->mProvider:Landroid/webkit/WebViewProvider;
@@ -2328,6 +2475,8 @@
 Landroid/widget/AbsListView;->mMaximumVelocity:I
 Landroid/widget/AbsListView;->mMotionPosition:I
 Landroid/widget/AbsListView;->mOnScrollListener:Landroid/widget/AbsListView$OnScrollListener;
+Landroid/widget/AbsListView;->mPendingCheckForLongPress:Landroid/widget/AbsListView$CheckForLongPress;
+Landroid/widget/AbsListView;->mPendingCheckForTap:Landroid/widget/AbsListView$CheckForTap;
 Landroid/widget/AbsListView;->mRecycler:Landroid/widget/AbsListView$RecycleBin;
 Landroid/widget/AbsListView;->mSelectionTopPadding:I
 Landroid/widget/AbsListView;->mSelectorPosition:I
@@ -2340,6 +2489,8 @@
 Landroid/widget/AbsListView$RecycleBin;->clear()V
 Landroid/widget/AbsListView$RecycleBin;->mRecyclerListener:Landroid/widget/AbsListView$RecyclerListener;
 Landroid/widget/AbsListView;->reportScrollStateChange(I)V
+Landroid/widget/AbsListView$SavedState;->firstId:J
+Landroid/widget/AbsListView$SavedState;->viewTop:I
 Landroid/widget/AbsListView;->smoothScrollBy(IIZZ)V
 Landroid/widget/AbsListView;->trackMotionScroll(II)Z
 Landroid/widget/AbsSeekBar;->mIsDragging:Z
@@ -2358,7 +2509,9 @@
 Landroid/widget/AutoCompleteTextView;->ensureImeVisible(Z)V
 Landroid/widget/AutoCompleteTextView;->mPopup:Landroid/widget/ListPopupWindow;
 Landroid/widget/AutoCompleteTextView;->setDropDownAlwaysVisible(Z)V
+Landroid/widget/AutoCompleteTextView;->setForceIgnoreOutsideTouch(Z)V
 Landroid/widget/CompoundButton;->mButtonDrawable:Landroid/graphics/drawable/Drawable;
+Landroid/widget/CompoundButton;->mOnCheckedChangeListener:Landroid/widget/CompoundButton$OnCheckedChangeListener;
 Landroid/widget/CursorAdapter;->mChangeObserver:Landroid/widget/CursorAdapter$ChangeObserver;
 Landroid/widget/CursorAdapter;->mDataSetObserver:Landroid/database/DataSetObserver;
 Landroid/widget/CursorAdapter;->mDataValid:Z
@@ -2369,6 +2522,7 @@
 Landroid/widget/Editor;->mShowCursor:J
 Landroid/widget/Editor;->mShowSoftInputOnFocus:Z
 Landroid/widget/ExpandableListView;->mChildDivider:Landroid/graphics/drawable/Drawable;
+Landroid/widget/ExpandableListView;->mGroupIndicator:Landroid/graphics/drawable/Drawable;
 Landroid/widget/FastScroller;->mContainerRect:Landroid/graphics/Rect;
 Landroid/widget/FastScroller;->mHeaderCount:I
 Landroid/widget/FastScroller;->mLongList:Z
@@ -2475,13 +2629,17 @@
 Landroid/widget/RemoteViews;->mergeRemoteViews(Landroid/widget/RemoteViews;)V
 Landroid/widget/RemoteViews;->mPortrait:Landroid/widget/RemoteViews;
 Landroid/widget/RemoteViews$ReflectionAction;->methodName:Ljava/lang/String;
+Landroid/widget/RemoteViews$ReflectionAction;->value:Ljava/lang/Object;
+Landroid/widget/RemoteViews$SetOnClickPendingIntent;->pendingIntent:Landroid/app/PendingIntent;
 Landroid/widget/ScrollBarDrawable;->mVerticalThumb:Landroid/graphics/drawable/Drawable;
 Landroid/widget/ScrollBarDrawable;->setHorizontalThumbDrawable(Landroid/graphics/drawable/Drawable;)V
 Landroid/widget/ScrollBarDrawable;->setVerticalThumbDrawable(Landroid/graphics/drawable/Drawable;)V
+Landroid/widget/Scroller;->mInterpolator:Landroid/view/animation/Interpolator;
 Landroid/widget/ScrollView;->mChildToScrollTo:Landroid/view/View;
 Landroid/widget/ScrollView;->mEdgeGlowBottom:Landroid/widget/EdgeEffect;
 Landroid/widget/ScrollView;->mEdgeGlowTop:Landroid/widget/EdgeEffect;
 Landroid/widget/ScrollView;->mIsBeingDragged:Z
+Landroid/widget/ScrollView;->mMinimumVelocity:I
 Landroid/widget/ScrollView;->mOverflingDistance:I
 Landroid/widget/ScrollView;->mOverscrollDistance:I
 Landroid/widget/ScrollView;->mScroller:Landroid/widget/OverScroller;
@@ -2495,7 +2653,11 @@
 Landroid/widget/Spinner;->mPopup:Landroid/widget/Spinner$SpinnerPopup;
 Landroid/widget/Switch;->mThumbDrawable:Landroid/graphics/drawable/Drawable;
 Landroid/widget/Switch;->mTrackDrawable:Landroid/graphics/drawable/Drawable;
+Landroid/widget/TabHost$IntentContentStrategy;->getContentView()Landroid/view/View;
+Landroid/widget/TabHost$IntentContentStrategy;->tabClosed()V
+Landroid/widget/TabHost;->mTabSpecs:Ljava/util/List;
 Landroid/widget/TabHost$TabSpec;->mContentStrategy:Landroid/widget/TabHost$ContentStrategy;
+Landroid/widget/TabWidget;->mSelectedTab:I
 Landroid/widget/TabWidget;->setTabSelectionListener(Landroid/widget/TabWidget$OnTabSelectionChanged;)V
 Landroid/widget/TextView;->assumeLayout()V
 Landroid/widget/TextView;->createEditorIfNeeded()V
@@ -2513,7 +2675,11 @@
 Landroid/widget/TextView;->mTextPaint:Landroid/text/TextPaint;
 Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;Landroid/widget/TextView$BufferType;ZI)V
 Landroid/widget/Toast;->getService()Landroid/app/INotificationManager;
+Landroid/widget/Toast;->getWindowParams()Landroid/view/WindowManager$LayoutParams;
+Landroid/widget/Toast;->mTN:Landroid/widget/Toast$TN;
 Landroid/widget/Toast;->sService:Landroid/app/INotificationManager;
+Landroid/widget/Toast$TN;->mNextView:Landroid/view/View;
+Landroid/widget/Toast$TN;->mParams:Landroid/view/WindowManager$LayoutParams;
 Landroid/widget/VideoView2;->getMediaController()Landroid/media/session/MediaController;
 Landroid/widget/VideoView2$OnViewTypeChangedListener;->onViewTypeChanged(Landroid/view/View;I)V
 Landroid/widget/VideoView2;->setOnViewTypeChangedListener(Landroid/widget/VideoView2$OnViewTypeChangedListener;)V
@@ -2596,6 +2762,7 @@
 Lcom/android/internal/app/IAppOpsService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IAppOpsService;
 Lcom/android/internal/app/IAppOpsService$Stub$Proxy;->checkOperation(IILjava/lang/String;)I
 Lcom/android/internal/app/IAppOpsService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Lcom/android/internal/app/IAppOpsService$Stub$Proxy;->setMode(IILjava/lang/String;I)V
 Lcom/android/internal/app/IBatteryStats;->getStatistics()[B
 Lcom/android/internal/app/IBatteryStats$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IBatteryStats;
 Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -2623,10 +2790,12 @@
 Lcom/android/internal/os/BatteryStatsImpl;->computeBatteryRealtime(JI)J
 Lcom/android/internal/os/BatteryStatsImpl;->computeBatteryUptime(JI)J
 Lcom/android/internal/os/BatteryStatsImpl;->CREATOR:Landroid/os/Parcelable$Creator;
+Lcom/android/internal/os/BatteryStatsImpl;->getBatteryRealtime(J)J
 Lcom/android/internal/os/BatteryStatsImpl;->getDischargeAmount(I)I
 Lcom/android/internal/os/BatteryStatsImpl;->getGlobalWifiRunningTime(JI)J
 Lcom/android/internal/os/BatteryStatsImpl;->getScreenOnTime(JI)J
 Lcom/android/internal/os/BatteryStatsImpl;->getUidStats()Landroid/util/SparseArray;
+Lcom/android/internal/os/BatteryStatsImpl;->getUidStatsLocked(I)Lcom/android/internal/os/BatteryStatsImpl$Uid;
 Lcom/android/internal/os/BatteryStatsImpl$Timer;->getCountLocked(I)I
 Lcom/android/internal/os/BatteryStatsImpl$Timer;->getTotalTimeLocked(JI)J
 Lcom/android/internal/os/BatteryStatsImpl$Uid;->getProcessStats()Landroid/util/ArrayMap;
@@ -2694,6 +2863,18 @@
 Lcom/android/internal/R$string;->megabyteShort:I
 Lcom/android/internal/R$string;->petabyteShort:I
 Lcom/android/internal/R$string;->terabyteShort:I
+Lcom/android/internal/R$styleable;->AbsListView_cacheColorHint:I
+Lcom/android/internal/R$styleable;->AbsListView_choiceMode:I
+Lcom/android/internal/R$styleable;->AbsListView_drawSelectorOnTop:I
+Lcom/android/internal/R$styleable;->AbsListView_fastScrollAlwaysVisible:I
+Lcom/android/internal/R$styleable;->AbsListView_fastScrollEnabled:I
+Lcom/android/internal/R$styleable;->AbsListView:[I
+Lcom/android/internal/R$styleable;->AbsListView_listSelector:I
+Lcom/android/internal/R$styleable;->AbsListView_scrollingCache:I
+Lcom/android/internal/R$styleable;->AbsListView_smoothScrollbar:I
+Lcom/android/internal/R$styleable;->AbsListView_stackFromBottom:I
+Lcom/android/internal/R$styleable;->AbsListView_textFilterEnabled:I
+Lcom/android/internal/R$styleable;->AbsListView_transcriptMode:I
 Lcom/android/internal/R$styleable;->AccountAuthenticator_accountPreferences:I
 Lcom/android/internal/R$styleable;->AccountAuthenticator_accountType:I
 Lcom/android/internal/R$styleable;->AccountAuthenticator_customTokens:I
@@ -2701,6 +2882,28 @@
 Lcom/android/internal/R$styleable;->AccountAuthenticator_icon:I
 Lcom/android/internal/R$styleable;->AccountAuthenticator_label:I
 Lcom/android/internal/R$styleable;->AccountAuthenticator_smallIcon:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_allowTaskReparenting:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_configChanges:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_description:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_enabled:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_excludeFromRecents:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_exported:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_hardwareAccelerated:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity:[I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_icon:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_immersive:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_label:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_launchMode:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_logo:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_name:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_noHistory:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_permission:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_process:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_screenOrientation:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_taskAffinity:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_theme:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_uiOptions:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_windowSoftInputMode:I
 Lcom/android/internal/R$styleable;->AndroidManifestApplication_enabled:I
 Lcom/android/internal/R$styleable;->AndroidManifestApplication_hardwareAccelerated:I
 Lcom/android/internal/R$styleable;->AndroidManifestApplication:[I
@@ -2712,8 +2915,21 @@
 Lcom/android/internal/R$styleable;->AndroidManifestApplication_supportsRtl:I
 Lcom/android/internal/R$styleable;->AndroidManifestApplication_theme:I
 Lcom/android/internal/R$styleable;->AndroidManifestApplication_uiOptions:I
+Lcom/android/internal/R$styleable;->AndroidManifestData:[I
 Lcom/android/internal/R$styleable;->AndroidManifest:[I
 Lcom/android/internal/R$styleable;->AndroidManifest_installLocation:I
+Lcom/android/internal/R$styleable;->AndroidManifestIntentFilter:[I
+Lcom/android/internal/R$styleable;->AndroidManifestIntentFilter_priority:I
+Lcom/android/internal/R$styleable;->AndroidManifestMetaData:[I
+Lcom/android/internal/R$styleable;->AndroidManifestMetaData_name:I
+Lcom/android/internal/R$styleable;->AndroidManifestMetaData_resource:I
+Lcom/android/internal/R$styleable;->AndroidManifestMetaData_value:I
+Lcom/android/internal/R$styleable;->AndroidManifestService_enabled:I
+Lcom/android/internal/R$styleable;->AndroidManifestService_exported:I
+Lcom/android/internal/R$styleable;->AndroidManifestService:[I
+Lcom/android/internal/R$styleable;->AndroidManifestService_name:I
+Lcom/android/internal/R$styleable;->AndroidManifestService_permission:I
+Lcom/android/internal/R$styleable;->AndroidManifestService_process:I
 Lcom/android/internal/R$styleable;->AndroidManifest_sharedUserId:I
 Lcom/android/internal/R$styleable;->AndroidManifestUsesPermission:[I
 Lcom/android/internal/R$styleable;->AndroidManifestUsesPermission_name:I
@@ -2727,6 +2943,7 @@
 Lcom/android/internal/R$styleable;->CheckBoxPreference_summaryOff:I
 Lcom/android/internal/R$styleable;->CheckBoxPreference_summaryOn:I
 Lcom/android/internal/R$styleable;->CompoundButton_button:I
+Lcom/android/internal/R$styleable;->CompoundButton_checked:I
 Lcom/android/internal/R$styleable;->CompoundButton:[I
 Lcom/android/internal/R$styleable;->DialogPreference_dialogTitle:I
 Lcom/android/internal/R$styleable;->DialogPreference:[I
@@ -2737,6 +2954,15 @@
 Lcom/android/internal/R$styleable;->ImageView_src:I
 Lcom/android/internal/R$styleable;->ListPreference_entries:I
 Lcom/android/internal/R$styleable;->ListPreference:[I
+Lcom/android/internal/R$styleable;->ListView_dividerHeight:I
+Lcom/android/internal/R$styleable;->ListView_divider:I
+Lcom/android/internal/R$styleable;->ListView_entries:I
+Lcom/android/internal/R$styleable;->ListView_footerDividersEnabled:I
+Lcom/android/internal/R$styleable;->ListView_headerDividersEnabled:I
+Lcom/android/internal/R$styleable;->ListView:[I
+Lcom/android/internal/R$styleable;->ListView_overScrollFooter:I
+Lcom/android/internal/R$styleable;->ListView_overScrollHeader:I
+Lcom/android/internal/R$styleable;->PopupWindow:[I
 Lcom/android/internal/R$styleable;->Preference_defaultValue:I
 Lcom/android/internal/R$styleable;->Preference_dependency:I
 Lcom/android/internal/R$styleable;->Preference_enabled:I
@@ -2765,12 +2991,15 @@
 Lcom/android/internal/R$styleable;->SyncAdapter_supportsUploading:I
 Lcom/android/internal/R$styleable;->SyncAdapter_userVisible:I
 Lcom/android/internal/R$styleable;->TabWidget:[I
+Lcom/android/internal/R$styleable;->TextAppearance:[I
 Lcom/android/internal/R$styleable;->TextView_drawableBottom:I
 Lcom/android/internal/R$styleable;->TextView_drawableLeft:I
 Lcom/android/internal/R$styleable;->TextView_drawableRight:I
 Lcom/android/internal/R$styleable;->TextView_drawableTop:I
 Lcom/android/internal/R$styleable;->TextView:[I
 Lcom/android/internal/R$styleable;->TextView_maxLines:I
+Lcom/android/internal/R$styleable;->TextView_textColorHint:I
+Lcom/android/internal/R$styleable;->TextView_textColor:I
 Lcom/android/internal/R$styleable;->View_background:I
 Lcom/android/internal/R$styleable;->ViewGroup_Layout:[I
 Lcom/android/internal/R$styleable;->ViewGroup_Layout_layout_height:I
@@ -2791,24 +3020,35 @@
 Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Lcom/android/internal/telephony/ISms$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ISms;
 Lcom/android/internal/telephony/ISub$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Lcom/android/internal/telephony/ITelephony;->answerRingingCall()V
 Lcom/android/internal/telephony/ITelephony;->call(Ljava/lang/String;Ljava/lang/String;)V
+Lcom/android/internal/telephony/ITelephony;->dial(Ljava/lang/String;)V
 Lcom/android/internal/telephony/ITelephony;->disableDataConnectivity()Z
 Lcom/android/internal/telephony/ITelephony;->enableDataConnectivity()Z
 Lcom/android/internal/telephony/ITelephony;->endCall()Z
+Lcom/android/internal/telephony/ITelephony;->getCallState()I
+Lcom/android/internal/telephony/ITelephony;->getDataState()I
 Lcom/android/internal/telephony/ITelephony;->isIdle(Ljava/lang/String;)Z
 Lcom/android/internal/telephony/ITelephony;->silenceRinger()V
 Lcom/android/internal/telephony/ITelephony$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ITelephony;
 Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->endCall()Z
 Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_call:I
+Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_endCall:I
 Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_getDeviceId:I
+Lcom/android/internal/telephony/SmsRawData;->CREATOR:Landroid/os/Parcelable$Creator;
+Lcom/android/internal/telephony/SmsRawData;-><init>([B)V
 Lcom/android/internal/textservice/ITextServicesManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Lcom/android/internal/util/AsyncChannel;->sendMessage(III)V
 Lcom/android/internal/util/FastPrintWriter;-><init>(Ljava/io/OutputStream;)V
 Lcom/android/internal/util/XmlUtils;->readMapXml(Ljava/io/InputStream;)Ljava/util/HashMap;
+Lcom/android/internal/util/XmlUtils;->skipCurrentTag(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/internal/util/XmlUtils;->writeMapXml(Ljava/util/Map;Ljava/io/OutputStream;)V
 Lcom/android/internal/view/IInputMethodManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodManager;
 Lcom/android/internal/view/IInputMethodManager$Stub$Proxy;->getEnabledInputMethodList()Ljava/util/List;
 Lcom/android/internal/view/IInputMethodManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Lcom/android/internal/view/InputBindResult;->CREATOR:Landroid/os/Parcelable$Creator;
+Lcom/android/internal/view/menu/MenuBuilder;-><init>(Landroid/content/Context;)V
 Lcom/android/internal/view/menu/MenuBuilder;->mContext:Landroid/content/Context;
 Lcom/android/internal/view/menu/MenuBuilder;->setCurrentMenuInfo(Landroid/view/ContextMenu$ContextMenuInfo;)V
 Lcom/android/internal/view/menu/MenuBuilder;->setOptionalIconsVisible(Z)V
@@ -2864,6 +3104,7 @@
 Lcom/android/org/conscrypt/ConscryptSocketBase;->setHandshakeTimeout(I)V
 Lcom/android/org/conscrypt/ConscryptSocketBase;->setHostname(Ljava/lang/String;)V
 Lcom/android/org/conscrypt/ConscryptSocketBase;->setSoWriteTimeout(I)V
+Lcom/android/org/conscrypt/ConscryptSocketBase;->socket:Ljava/net/Socket;
 Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getAlpnSelectedProtocol()[B
 Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getChannelId()[B
 Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getHostname()Ljava/lang/String;
@@ -2886,10 +3127,12 @@
 Ldalvik/system/BaseDexClassLoader;->pathList:Ldalvik/system/DexPathList;
 Ldalvik/system/BlockGuard;->getThreadPolicy()Ldalvik/system/BlockGuard$Policy;
 Ldalvik/system/BlockGuard$Policy;->onNetwork()V
+Ldalvik/system/BlockGuard$Policy;->onReadFromDisk()V
 Ldalvik/system/CloseGuard;->close()V
 Ldalvik/system/CloseGuard;->get()Ldalvik/system/CloseGuard;
 Ldalvik/system/CloseGuard;->open(Ljava/lang/String;)V
 Ldalvik/system/CloseGuard;->warnIfOpen()V
+Ldalvik/system/DexFile$DFEnum;->mNameList:[Ljava/lang/String;
 Ldalvik/system/DexFile;->getClassNameList(Ljava/lang/Object;)[Ljava/lang/String;
 Ldalvik/system/DexFile;->isBackedByOatFile()Z
 Ldalvik/system/DexFile;->loadClassBinaryName(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/util/List;)Ljava/lang/Class;
@@ -2898,6 +3141,7 @@
 Ldalvik/system/DexFile;->mInternalCookie:Ljava/lang/Object;
 Ldalvik/system/DexFile;->openDexFile(Ljava/lang/String;Ljava/lang/String;ILjava/lang/ClassLoader;[Ldalvik/system/DexPathList$Element;)Ljava/lang/Object;
 Ldalvik/system/DexPathList;->addDexPath(Ljava/lang/String;Ljava/io/File;)V
+Ldalvik/system/DexPathList;->definingContext:Ljava/lang/ClassLoader;
 Ldalvik/system/DexPathList;->dexElements:[Ldalvik/system/DexPathList$Element;
 Ldalvik/system/DexPathList$Element;->dexFile:Ldalvik/system/DexFile;
 Ldalvik/system/DexPathList$Element;-><init>(Ldalvik/system/DexFile;Ljava/io/File;)V
@@ -2918,6 +3162,7 @@
 Ldalvik/system/VMRuntime;->addressOf(Ljava/lang/Object;)J
 Ldalvik/system/VMRuntime;->clearGrowthLimit()V
 Ldalvik/system/VMRuntime;->getCurrentInstructionSet()Ljava/lang/String;
+Ldalvik/system/VMRuntime;->getInstructionSet(Ljava/lang/String;)Ljava/lang/String;
 Ldalvik/system/VMRuntime;->getRuntime()Ldalvik/system/VMRuntime;
 Ldalvik/system/VMRuntime;->is64Bit()Z
 Ldalvik/system/VMRuntime;->newNonMovableArray(Ljava/lang/Class;I)Ljava/lang/Object;
@@ -2935,7 +3180,9 @@
 Ldalvik/system/VMStack;->getStackClass2()Ljava/lang/Class;
 Ljava/io/FileDescriptor;->descriptor:I
 Ljava/io/FileDescriptor;->getInt$()I
+Ljava/io/FileDescriptor;->isSocket$()Z
 Ljava/io/FileDescriptor;->setInt$(I)V
+Ljava/io/File;->fs:Ljava/io/FileSystem;
 Ljava/io/FileInputStream;->fd:Ljava/io/FileDescriptor;
 Ljava/io/FileOutputStream;->fd:Ljava/io/FileDescriptor;
 Ljava/io/ObjectStreamClass;->getConstructorId(Ljava/lang/Class;)J
@@ -2945,8 +3192,10 @@
 Ljava/lang/Boolean;->value:Z
 Ljava/lang/Byte;->value:B
 Ljava/lang/Character;->value:C
+Ljava/lang/Class;->accessFlags:I
 Ljava/lang/Class;->dexCache:Ljava/lang/Object;
 Ljava/lang/Class;->dexClassDefIndex:I
+Ljava/lang/Class;->ifTable:[Ljava/lang/Object;
 Ljava/lang/ClassLoader;->parent:Ljava/lang/ClassLoader;
 Ljava/lang/Daemons$Daemon;->isRunning()Z
 Ljava/lang/Daemons$Daemon;->start()V
@@ -3018,6 +3267,7 @@
 Ljava/net/Inet6Address;-><init>()V
 Ljava/net/InetAddress;->clearDnsCache()V
 Ljava/net/InetAddress;->holder:Ljava/net/InetAddress$InetAddressHolder;
+Ljava/net/InetAddress;->holder()Ljava/net/InetAddress$InetAddressHolder;
 Ljava/net/InetAddress$InetAddressHolder;->address:I
 Ljava/net/InetAddress$InetAddressHolder;->family:I
 Ljava/net/InetAddress$InetAddressHolder;->hostName:Ljava/lang/String;
@@ -3026,6 +3276,8 @@
 Ljava/net/InetAddress;->parseNumericAddress(Ljava/lang/String;)Ljava/net/InetAddress;
 Ljava/net/Socket;->getFileDescriptor$()Ljava/io/FileDescriptor;
 Ljava/net/Socket;->impl:Ljava/net/SocketImpl;
+Ljava/net/SocketImpl;->serverSocket:Ljava/net/ServerSocket;
+Ljava/net/SocketImpl;->socket:Ljava/net/Socket;
 Ljava/net/URI;->host:Ljava/lang/String;
 Ljava/net/URL;->handler:Ljava/net/URLStreamHandler;
 Ljava/net/URL;->handlers:Ljava/util/Hashtable;
@@ -3060,11 +3312,16 @@
 Ljava/util/Collections$UnmodifiableCollection;->c:Ljava/util/Collection;
 Ljava/util/Collections$UnmodifiableMap;->m:Ljava/util/Map;
 Ljava/util/concurrent/ConcurrentHashMap$BaseIterator;->hasMoreElements()Z
+Ljava/util/concurrent/Executors$RunnableAdapter;->task:Ljava/lang/Runnable;
 Ljava/util/concurrent/FutureTask;->callable:Ljava/util/concurrent/Callable;
+Ljava/util/concurrent/FutureTask;->EXCEPTIONAL:I
+Ljava/util/concurrent/FutureTask;->outcome:Ljava/lang/Object;
+Ljava/util/concurrent/FutureTask;->state:I
 Ljava/util/concurrent/LinkedBlockingQueue;->capacity:I
 Ljava/util/EnumMap;->keyType:Ljava/lang/Class;
 Ljava/util/EnumSet;->elementType:Ljava/lang/Class;
 Ljava/util/HashMap$HashIterator;->hasNext()Z
+Ljava/util/jar/JarFile;->manifest:Ljava/util/jar/Manifest;
 Ljava/util/LinkedHashMap;->eldest()Ljava/util/Map$Entry;
 Ljava/util/LinkedHashMap$LinkedHashIterator;->hasNext()Z
 Ljava/util/Locale;->createConstant(Ljava/lang/String;Ljava/lang/String;)Ljava/util/Locale;
@@ -3087,11 +3344,15 @@
 Ljava/util/zip/ZipFile;->jzfile:J
 Ljavax/net/ssl/SSLServerSocketFactory;->defaultServerSocketFactory:Ljavax/net/ssl/SSLServerSocketFactory;
 Ljavax/net/ssl/SSLSocketFactory;->defaultSocketFactory:Ljavax/net/ssl/SSLSocketFactory;
+Llibcore/util/BasicLruCache;->map:Ljava/util/LinkedHashMap;
 Llibcore/util/ZoneInfo;->mTransitions:[J
 Lorg/apache/http/conn/ssl/SSLSocketFactory;-><init>(Ljavax/net/ssl/SSLSocketFactory;)V
 Lorg/apache/http/conn/ssl/SSLSocketFactory;-><init>()V
+Lorg/ccil/cowan/tagsoup/AttributesImpl;->data:[Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/AttributesImpl;->length:I
 Lorg/json/JSONArray;->values:Ljava/util/List;
 Lorg/json/JSONObject;->append(Ljava/lang/String;Ljava/lang/Object;)Lorg/json/JSONObject;
 Lorg/json/JSONObject;->keySet()Ljava/util/Set;
 Lorg/json/JSONObject;->writeTo(Lorg/json/JSONStringer;)V
+Lorg/w3c/dom/traversal/NodeIterator;->nextNode()Lorg/w3c/dom/Node;
 Lsun/misc/Unsafe;->theUnsafe:Lsun/misc/Unsafe;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index f5e138c..71b88fa 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1713,6 +1713,9 @@
                 Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " holds " + permission);
                 return PackageManager.PERMISSION_GRANTED;
             }
+            Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " does not hold "
+                    + permission);
+            return PackageManager.PERMISSION_DENIED;
         }
 
         try {
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 30f2697..4a7cf62 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -463,7 +463,11 @@
 
     /**
      * Returns the user specified importance e.g. {@link NotificationManager#IMPORTANCE_LOW} for
-     * notifications posted to this channel.
+     * notifications posted to this channel. Note: This value might be >
+     * {@link NotificationManager#IMPORTANCE_NONE}, but notifications posted to this channel will
+     * not be shown to the user if the parent {@link NotificationChannelGroup} or app is blocked.
+     * See {@link NotificationChannelGroup#isBlocked()} and
+     * {@link NotificationManager#areNotificationsEnabled()}.
      */
     public int getImportance() {
         return mImportance;
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index 16166f7..0fa3c7f 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -145,7 +145,9 @@
 
     /**
      * Returns whether or not notifications posted to {@link NotificationChannel channels} belonging
-     * to this group are blocked.
+     * to this group are blocked. This value is independent of
+     * {@link NotificationManager#areNotificationsEnabled()} and
+     * {@link NotificationChannel#getImportance()}.
      */
     public boolean isBlocked() {
         return mBlocked;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 1534a15..b64aae5 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2747,110 +2747,6 @@
     }
 
     /**
-     * The maximum number of characters allowed in the password blacklist.
-     */
-    private static final int PASSWORD_BLACKLIST_CHARACTER_LIMIT = 128 * 1000;
-
-    /**
-     * Throws an exception if the password blacklist is too large.
-     *
-     * @hide
-     */
-    public static void enforcePasswordBlacklistSize(List<String> blacklist) {
-        if (blacklist == null) {
-            return;
-        }
-        long characterCount = 0;
-        for (final String item : blacklist) {
-            characterCount += item.length();
-        }
-        if (characterCount > PASSWORD_BLACKLIST_CHARACTER_LIMIT) {
-            throw new IllegalArgumentException("128 thousand blacklist character limit exceeded by "
-                      + (characterCount - PASSWORD_BLACKLIST_CHARACTER_LIMIT) + " characters");
-        }
-    }
-
-    /**
-     * Called by an application that is administering the device to blacklist passwords.
-     * <p>
-     * Any blacklisted password or PIN is prevented from being enrolled by the user or the admin.
-     * Note that the match against the blacklist is case insensitive. The blacklist applies for all
-     * password qualities requested by {@link #setPasswordQuality} however it is not taken into
-     * consideration by {@link #isActivePasswordSufficient}.
-     * <p>
-     * The blacklist can be cleared by passing {@code null} or an empty list. The blacklist is
-     * given a name that is used to track which blacklist is currently set by calling {@link
-     * #getPasswordBlacklistName}. If the blacklist is being cleared, the name is ignored and {@link
-     * #getPasswordBlacklistName} will return {@code null}. The name can only be {@code null} when
-     * the blacklist is being cleared.
-     * <p>
-     * The blacklist is limited to a total of 128 thousand characters rather than limiting to a
-     * number of entries.
-     * <p>
-     * This method can be called on the {@link DevicePolicyManager} instance returned by
-     * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
-     * profile.
-     *
-     * @param admin the {@link DeviceAdminReceiver} this request is associated with
-     * @param name name to associate with the blacklist
-     * @param blacklist list of passwords to blacklist or {@code null} to clear the blacklist
-     * @return whether the new blacklist was successfully installed
-     * @throws SecurityException if {@code admin} is not a device or profile owner
-     * @throws IllegalArgumentException if the blacklist surpasses the character limit
-     * @throws NullPointerException if {@code name} is {@code null} when setting a non-empty list
-     *
-     * @see #getPasswordBlacklistName
-     * @see #isActivePasswordSufficient
-     * @see #resetPasswordWithToken
-     */
-    public boolean setPasswordBlacklist(@NonNull ComponentName admin, @Nullable String name,
-            @Nullable List<String> blacklist) {
-        enforcePasswordBlacklistSize(blacklist);
-
-        try {
-            return mService.setPasswordBlacklist(admin, name, blacklist, mParentInstance);
-        } catch (RemoteException re) {
-            throw re.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Get the name of the password blacklist set by the given admin.
-     *
-     * @param admin the {@link DeviceAdminReceiver} this request is associated with
-     * @return the name of the blacklist or {@code null} if no blacklist is set
-     *
-     * @see #setPasswordBlacklist
-     */
-    public @Nullable String getPasswordBlacklistName(@NonNull ComponentName admin) {
-        try {
-            return mService.getPasswordBlacklistName(admin, myUserId(), mParentInstance);
-        } catch (RemoteException re) {
-            throw re.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Test if a given password is blacklisted.
-     *
-     * @param userId the user to valiate for
-     * @param password the password to check against the blacklist
-     * @return whether the password is blacklisted
-     *
-     * @see #setPasswordBlacklist
-     *
-     * @hide
-     */
-    @RequiresPermission(android.Manifest.permission.TEST_BLACKLISTED_PASSWORD)
-    public boolean isPasswordBlacklisted(@UserIdInt int userId, @NonNull String password) {
-        try {
-            return mService.isPasswordBlacklisted(userId, password);
-        } catch (RemoteException re) {
-            throw re.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Determine whether the current password the user has set is sufficient to meet the policy
      * requirements (e.g. quality, minimum length) that have been requested by the admins of this
      * user and its participating profiles. Restrictions on profiles that have a separate challenge
@@ -7326,11 +7222,12 @@
     public @interface SystemSettingsWhitelist {}
 
     /**
-     * Called by device owner to update {@link android.provider.Settings.System} settings.
-     * Validation that the value of the setting is in the correct form for the setting type should
-     * be performed by the caller.
+     * Called by a device or profile owner to update {@link android.provider.Settings.System}
+     * settings. Validation that the value of the setting is in the correct form for the setting
+     * type should be performed by the caller.
      * <p>
-     * The settings that can be updated with this method are:
+     * The settings that can be updated by a device owner or profile owner of secondary user with
+     * this method are:
      * <ul>
      * <li>{@link android.provider.Settings.System#SCREEN_BRIGHTNESS}</li>
      * <li>{@link android.provider.Settings.System#SCREEN_BRIGHTNESS_MODE}</li>
@@ -7342,7 +7239,7 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param setting The name of the setting to update.
      * @param value The value to update the setting to.
-     * @throws SecurityException if {@code admin} is not a device owner.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public void setSystemSetting(@NonNull ComponentName admin,
             @NonNull @SystemSettingsWhitelist String setting, String value) {
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 4b39a9a..37508cd 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -79,10 +79,6 @@
 
     long getPasswordExpiration(in ComponentName who, int userHandle, boolean parent);
 
-    boolean setPasswordBlacklist(in ComponentName who, String name, in List<String> blacklist, boolean parent);
-    String getPasswordBlacklistName(in ComponentName who, int userId, boolean parent);
-    boolean isPasswordBlacklisted(int userId, String password);
-
     boolean isActivePasswordSufficient(int userHandle, boolean parent);
     boolean isProfileActivePasswordSufficientForParent(int userHandle);
     boolean isUsingUnifiedPassword(in ComponentName admin);
diff --git a/core/java/android/app/slice/Slice.java b/core/java/android/app/slice/Slice.java
index 95bb1f6..fc3b38d 100644
--- a/core/java/android/app/slice/Slice.java
+++ b/core/java/android/app/slice/Slice.java
@@ -70,6 +70,7 @@
             HINT_ERROR,
             HINT_TTL,
             HINT_LAST_UPDATED,
+            HINT_PERMISSION_REQUEST,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface SliceHint {}
@@ -184,6 +185,11 @@
      */
     public static final String HINT_LAST_UPDATED = "last_updated";
     /**
+     * A hint to indicate that this slice represents a permission request for showing
+     * slices.
+     */
+    public static final String HINT_PERMISSION_REQUEST = "permission_request";
+    /**
      * Key to retrieve an extra added to an intent when a control is changed.
      */
     public static final String EXTRA_TOGGLE_STATE = "android.app.slice.extra.TOGGLE_STATE";
diff --git a/core/java/android/app/slice/SliceManager.java b/core/java/android/app/slice/SliceManager.java
index 1afe53d..88b198b 100644
--- a/core/java/android/app/slice/SliceManager.java
+++ b/core/java/android/app/slice/SliceManager.java
@@ -81,6 +81,17 @@
      * An activity can be statically linked to a slice uri by including a meta-data item
      * for this key that contains a valid slice uri for the same application declaring
      * the activity.
+     *
+     * <pre class="prettyprint">
+     * {@literal
+     * <activity android:name="com.example.mypkg.MyActivity">
+     *     <meta-data android:name="android.metadata.SLICE_URI"
+     *                android:value="content://com.example.mypkg/main_slice" />
+     *  </activity>}
+     * </pre>
+     *
+     * @see #mapIntentToUri(Intent)
+     * @see SliceProvider#onMapIntentToUri(Intent)
      */
     public static final String SLICE_METADATA_KEY = "android.metadata.SLICE_URI";
 
@@ -257,16 +268,17 @@
      * <p>
      * This goes through a several stage resolution process to determine if any slice
      * can represent this intent.
-     *  - If the intent contains data that {@link ContentResolver#getType} is
-     *  {@link SliceProvider#SLICE_TYPE} then the data will be returned.
-     *  - If the intent with {@link #CATEGORY_SLICE} added resolves to a provider, then
+     * <ol>
+     *  <li> If the intent contains data that {@link ContentResolver#getType} is
+     *  {@link SliceProvider#SLICE_TYPE} then the data will be returned.</li>
+     *  <li>If the intent with {@link #CATEGORY_SLICE} added resolves to a provider, then
      *  the provider will be asked to {@link SliceProvider#onMapIntentToUri} and that result
-     *  will be returned.
-     *  - Lastly, if the intent explicitly points at an activity, and that activity has
+     *  will be returned.</li>
+     *  <li>Lastly, if the intent explicitly points at an activity, and that activity has
      *  meta-data for key {@link #SLICE_METADATA_KEY}, then the Uri specified there will be
-     *  returned.
-     *  - If no slice is found, then {@code null} is returned.
-     *
+     *  returned.</li>
+     *  <li>If no slice is found, then {@code null} is returned.</li>
+     * </ol>
      * @param intent The intent associated with a slice.
      * @return The Slice Uri provided by the app or null if none exists.
      * @see Slice
diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
index bf856b7..bbeb3849 100644
--- a/core/java/android/app/slice/SliceProvider.java
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -428,15 +428,17 @@
         } finally {
             Handler.getMain().removeCallbacks(mAnr);
         }
-        return new Slice.Builder(sliceUri)
-                .addAction(action,
-                        new Slice.Builder(sliceUri.buildUpon().appendPath("permission").build())
-                                .addText(getPermissionString(context, callingPackage), null,
-                                        Collections.emptyList())
-                                .build(),
-                        null)
-                .addHints(Arrays.asList(Slice.HINT_LIST_ITEM))
-                .build();
+        Slice.Builder parent = new Slice.Builder(sliceUri);
+        Slice.Builder childAction = new Slice.Builder(parent)
+                .addHints(Arrays.asList(Slice.HINT_TITLE, Slice.HINT_SHORTCUT))
+                .addAction(action, new Slice.Builder(parent).build(), null);
+
+        parent.addSubSlice(new Slice.Builder(sliceUri.buildUpon().appendPath("permission").build())
+                .addText(getPermissionString(context, callingPackage), null,
+                        Collections.emptyList())
+                .addSubSlice(childAction.build(), null)
+                .build(), null);
+        return parent.addHints(Arrays.asList(Slice.HINT_PERMISSION_REQUEST)).build();
     }
 
     /**
diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java
index da36157..e315e91 100644
--- a/core/java/android/app/usage/NetworkStats.java
+++ b/core/java/android/app/usage/NetworkStats.java
@@ -24,7 +24,6 @@
 import android.net.NetworkTemplate;
 import android.net.TrafficStats;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.util.IntArray;
 import android.util.Log;
 
@@ -98,9 +97,8 @@
 
     /** @hide */
     NetworkStats(Context context, NetworkTemplate template, int flags, long startTimestamp,
-            long endTimestamp) throws RemoteException, SecurityException {
-        final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
-                ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+            long endTimestamp, INetworkStatsService statsService)
+            throws RemoteException, SecurityException {
         // Open network stats session
         mSession = statsService.openSessionForUsageStats(flags, context.getOpPackageName());
         mCloseGuard.open("close");
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 5576e86..2357637 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -37,6 +37,8 @@
 import android.os.ServiceManager.ServiceNotFoundException;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 /**
  * Provides access to network usage history and statistics. Usage data is collected in
  * discrete bins of time called 'Buckets'. See {@link NetworkStats.Bucket} for details.
@@ -107,9 +109,15 @@
      * {@hide}
      */
     public NetworkStatsManager(Context context) throws ServiceNotFoundException {
+        this(context, INetworkStatsService.Stub.asInterface(
+                ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE)));
+    }
+
+    /** @hide */
+    @VisibleForTesting
+    public NetworkStatsManager(Context context, INetworkStatsService service) {
         mContext = context;
-        mService = INetworkStatsService.Stub.asInterface(
-                ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE));
+        mService = service;
         setPollOnOpen(true);
     }
 
@@ -135,7 +143,8 @@
     public Bucket querySummaryForDevice(NetworkTemplate template,
             long startTime, long endTime) throws SecurityException, RemoteException {
         Bucket bucket = null;
-        NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime);
+        NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime,
+                mService);
         bucket = stats.getDeviceSummaryForNetwork();
 
         stats.close();
@@ -208,7 +217,7 @@
         }
 
         NetworkStats stats;
-        stats = new NetworkStats(mContext, template, mFlags, startTime, endTime);
+        stats = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
         stats.startSummaryEnumeration();
 
         stats.close();
@@ -245,7 +254,7 @@
         }
 
         NetworkStats result;
-        result = new NetworkStats(mContext, template, mFlags, startTime, endTime);
+        result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
         result.startSummaryEnumeration();
 
         return result;
@@ -295,7 +304,7 @@
 
         NetworkStats result;
         try {
-            result = new NetworkStats(mContext, template, mFlags, startTime, endTime);
+            result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
             result.startHistoryEnumeration(uid, tag);
         } catch (RemoteException e) {
             Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag, e);
@@ -341,7 +350,7 @@
         }
 
         NetworkStats result;
-        result = new NetworkStats(mContext, template, mFlags, startTime, endTime);
+        result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
         result.startUserUidEnumeration();
         return result;
     }
@@ -451,19 +460,20 @@
     }
 
     private static NetworkTemplate createTemplate(int networkType, String subscriberId) {
-        NetworkTemplate template = null;
+        final NetworkTemplate template;
         switch (networkType) {
-            case ConnectivityManager.TYPE_MOBILE: {
-                template = NetworkTemplate.buildTemplateMobileAll(subscriberId);
-                } break;
-            case ConnectivityManager.TYPE_WIFI: {
+            case ConnectivityManager.TYPE_MOBILE:
+                template = subscriberId == null
+                        ? NetworkTemplate.buildTemplateMobileWildcard()
+                        : NetworkTemplate.buildTemplateMobileAll(subscriberId);
+                break;
+            case ConnectivityManager.TYPE_WIFI:
                 template = NetworkTemplate.buildTemplateWifiWildcard();
-                } break;
-            default: {
+                break;
+            default:
                 throw new IllegalArgumentException("Cannot create template for network type "
                         + networkType + ", subscriberId '"
                         + NetworkIdentity.scrubSubscriberId(subscriberId) + "'.");
-            }
         }
         return template;
     }
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index d272652..eafe91a 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -183,10 +183,13 @@
     public static final int REASON_SUB_USAGE_SLICE_PINNED       = 0x0009;
     /** @hide */
     public static final int REASON_SUB_USAGE_SLICE_PINNED_PRIV  = 0x000A;
+    /** @hide */
+    public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_START = 0x000B;
 
     /** @hide */
     public static final int REASON_SUB_PREDICTED_RESTORED       = 0x0001;
 
+
     /** @hide */
     @IntDef(flag = false, prefix = { "STANDBY_BUCKET_" }, value = {
             STANDBY_BUCKET_EXEMPTED,
@@ -665,6 +668,9 @@
                     case REASON_SUB_USAGE_SLICE_PINNED_PRIV:
                         sb.append("slpp");
                         break;
+                    case REASON_SUB_USAGE_EXEMPTED_SYNC_START:
+                        sb.append("es");
+                        break;
                 }
                 break;
         }
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index 09ced26..b8628a4 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -243,4 +243,12 @@
      */
     public abstract void reportAppJobState(String packageName, @UserIdInt int userId,
             int numDeferredJobs, long timeSinceLastJobRun);
+
+    /**
+     * Report a sync that was scheduled by an active app is about to be executed.
+     *
+     * @param packageName name of the package that owns the sync adapter.
+     * @param userId which user the app is associated with
+     */
+    public abstract void reportExemptedSyncStart(String packageName, @UserIdInt int userId);
 }
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 440103a..9f3df37 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -166,24 +166,13 @@
     public static final String SYNC_EXTRAS_DISALLOW_METERED = "allow_metered";
 
     /**
-     * {@hide} Flag only used by the requestsync command to treat a request as if it was made by
-     * a foreground app.
+     * {@hide} Integer extra containing a SyncExemption flag.
      *
      * Only the system and the shell user can set it.
      *
      * This extra is "virtual". Once passed to the system server, it'll be removed from the bundle.
      */
-    public static final String SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC = "force_fg_sync";
-
-    /**
-     * {@hide} Flag only used by the requestsync command to treat a request as if it was made by
-     * a background app.
-     *
-     * Only the system and the shell user can set it.
-     *
-     * This extra is "virtual". Once passed to the system server, it'll be removed from the bundle.
-     */
-    public static final String SYNC_VIRTUAL_EXTRAS_FORCE_BG_SYNC = "force_bg_sync";
+    public static final String SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG = "v_exemption";
 
     /**
      * Set by the SyncManager to request that the SyncAdapter initialize itself for
@@ -525,6 +514,38 @@
      */
     public static final int NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS = 1<<1;
 
+    /**
+     * No exception, throttled by app standby normally.
+     * @hide
+     */
+    public static final int SYNC_EXEMPTION_NONE = 0;
+
+    /**
+     * When executing a sync with this exemption, we'll put the target app in the ACTIVE bucket
+     * for 10 minutes. This will allow the sync adapter to schedule/run further syncs and jobs.
+     *
+     * Note this will still *not* let RARE apps to run syncs, because they still won't get network
+     * connection.
+     * @hide
+     */
+    public static final int SYNC_EXEMPTION_ACTIVE = 1;
+
+    /**
+     * In addition to {@link #SYNC_EXEMPTION_ACTIVE}, we put the sync adapter app in the
+     * temp whitelist for 10 minutes, so that even RARE apps can run syncs right away.
+     * @hide
+     */
+    public static final int SYNC_EXEMPTION_ACTIVE_WITH_TEMP = 2;
+
+    /** @hide */
+    @IntDef(flag = false, prefix = { "SYNC_EXEMPTION_" }, value = {
+            SYNC_EXEMPTION_NONE,
+            SYNC_EXEMPTION_ACTIVE,
+            SYNC_EXEMPTION_ACTIVE_WITH_TEMP,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SyncExemption {}
+
     // Always log queries which take 500ms+; shorter queries are
     // sampled accordingly.
     private static final boolean ENABLE_CONTENT_SAMPLE = false;
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index a3b2d22..efb9517 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -535,6 +535,19 @@
     }
 
     /**
+     * Set the level of color saturation to apply to the display.
+     * @param level The amount of saturation to apply, between 0 and 1 inclusive.
+     * 0 produces a grayscale image, 1 is normal.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_SATURATION)
+    public void setSaturationLevel(float level) {
+        mGlobal.setSaturationLevel(level);
+    }
+
+    /**
      * Creates a virtual display.
      *
      * @see #createVirtualDisplay(String, int, int, int, Surface, int,
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 1f67a6b..2d0ef2f 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -384,6 +384,17 @@
         }
     }
 
+    /**
+     * Set the level of color saturation to apply to the display.
+     */
+    public void setSaturationLevel(float level) {
+        try {
+            mDm.setSaturationLevel(level);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
     public VirtualDisplay createVirtualDisplay(Context context, MediaProjection projection,
             String name, int width, int height, int densityDpi, Surface surface, int flags,
             VirtualDisplay.Callback callback, Handler handler, String uniqueId) {
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 9fcb9d3..b77de748 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -65,6 +65,9 @@
     // Requires CONFIGURE_DISPLAY_COLOR_MODE
     void requestColorMode(int displayId, int colorMode);
 
+    // Requires CONTROL_DISPLAY_SATURATION
+    void setSaturationLevel(float level);
+
     // Requires CAPTURE_VIDEO_OUTPUT, CAPTURE_SECURE_VIDEO_OUTPUT, or an appropriate
     // MediaProjection token for certain combinations of flags.
     int createVirtualDisplay(in IVirtualDisplayCallback callback,
diff --git a/core/java/android/hardware/radio/ProgramList.java b/core/java/android/hardware/radio/ProgramList.java
index b2aa9ba..e6f523c 100644
--- a/core/java/android/hardware/radio/ProgramList.java
+++ b/core/java/android/hardware/radio/ProgramList.java
@@ -263,6 +263,17 @@
         /**
          * @hide for framework use only
          */
+        public Filter() {
+            mIdentifierTypes = Collections.emptySet();
+            mIdentifiers = Collections.emptySet();
+            mIncludeCategories = false;
+            mExcludeModifications = false;
+            mVendorFilter = null;
+        }
+
+        /**
+         * @hide for framework use only
+         */
         public Filter(@Nullable Map<String, String> vendorFilter) {
             mIdentifierTypes = Collections.emptySet();
             mIdentifiers = Collections.emptySet();
diff --git a/core/java/android/hardware/radio/TunerAdapter.java b/core/java/android/hardware/radio/TunerAdapter.java
index 85f3115..be2846f 100644
--- a/core/java/android/hardware/radio/TunerAdapter.java
+++ b/core/java/android/hardware/radio/TunerAdapter.java
@@ -60,6 +60,7 @@
                 mLegacyListProxy.close();
                 mLegacyListProxy = null;
             }
+            mCallback.close();
         }
         try {
             mTuner.close();
@@ -278,6 +279,7 @@
             try {
                 mTuner.startProgramListUpdates(filter);
             } catch (UnsupportedOperationException ex) {
+                Log.i(TAG, "Program list is not supported with this hardware");
                 return null;
             } catch (RemoteException ex) {
                 mCallback.setProgramListObserver(null, () -> { });
diff --git a/core/java/android/hardware/radio/TunerCallbackAdapter.java b/core/java/android/hardware/radio/TunerCallbackAdapter.java
index 7437c40..0fb93e5 100644
--- a/core/java/android/hardware/radio/TunerCallbackAdapter.java
+++ b/core/java/android/hardware/radio/TunerCallbackAdapter.java
@@ -53,6 +53,12 @@
         }
     }
 
+    void close() {
+        synchronized (mLock) {
+            if (mProgramList != null) mProgramList.close();
+        }
+    }
+
     void setProgramListObserver(@Nullable ProgramList programList,
             @NonNull ProgramList.OnCloseListener closeListener) {
         Objects.requireNonNull(closeListener);
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index e07f586..80b1c3d 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -861,6 +861,10 @@
      * You should always check {@link NetworkInfo#isConnected()} before initiating
      * network traffic. This may return {@code null} when there is no default
      * network.
+     * Note that if the default network is a VPN, this method will return the
+     * NetworkInfo for one of its underlying networks instead, or null if the
+     * VPN agent did not specify any. Apps interested in learning about VPNs
+     * should use {@link #getNetworkInfo(android.net.Network)} instead.
      *
      * @return a {@link NetworkInfo} object for the current default network
      *        or {@code null} if no default network is currently active
@@ -1018,7 +1022,11 @@
      *        which you're interested.
      * @return a {@link NetworkInfo} object for the requested
      *        network type or {@code null} if the type is not
-     *        supported by the device.
+     *        supported by the device. If {@code networkType} is
+     *        TYPE_VPN and a VPN is active for the calling app,
+     *        then this method will try to return one of the
+     *        underlying networks for the VPN or null if the
+     *        VPN agent didn't specify any.
      *
      * @deprecated This method does not support multiple connected networks
      *             of the same type. Use {@link #getAllNetworks} and
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index 972b9c0..a88fe04 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -305,6 +305,19 @@
      * will throw IOException if the user deactivates the transform (by calling {@link
      * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}.
      *
+     * <p>Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an
+     * applied transform before completion of graceful shutdown may result in the shutdown sequence
+     * failing to complete. As such, applications requiring graceful shutdown MUST close the socket
+     * prior to deactivating the applied transform. Socket closure may be performed asynchronously
+     * (in batches), so the returning of a close function does not guarantee shutdown of a socket.
+     * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is
+     * sufficient to ensure shutdown.
+     *
+     * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}),
+     * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST]
+     * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the
+     * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped.
+     *
      * <h4>Rekey Procedure</h4>
      *
      * <p>When applying a new tranform to a socket in the outbound direction, the previous transform
@@ -373,6 +386,19 @@
      * will throw IOException if the user deactivates the transform (by calling {@link
      * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}.
      *
+     * <p>Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an
+     * applied transform before completion of graceful shutdown may result in the shutdown sequence
+     * failing to complete. As such, applications requiring graceful shutdown MUST close the socket
+     * prior to deactivating the applied transform. Socket closure may be performed asynchronously
+     * (in batches), so the returning of a close function does not guarantee shutdown of a socket.
+     * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is
+     * sufficient to ensure shutdown.
+     *
+     * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}),
+     * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST]
+     * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the
+     * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped.
+     *
      * <h4>Rekey Procedure</h4>
      *
      * <p>When applying a new tranform to a socket in the outbound direction, the previous transform
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index 5df168d..15a0ee5 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -26,6 +26,8 @@
 import com.android.okhttp.internalandroidapi.Dns;
 import com.android.okhttp.internalandroidapi.HttpURLConnectionFactory;
 
+import libcore.io.IoUtils;
+
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.net.DatagramSocket;
@@ -77,6 +79,11 @@
             httpKeepAlive ? Integer.parseInt(System.getProperty("http.maxConnections", "5")) : 0;
     private static final long httpKeepAliveDurationMs =
             Long.parseLong(System.getProperty("http.keepAliveDuration", "300000"));  // 5 minutes.
+    // Value used to obfuscate network handle longs.
+    // The HANDLE_MAGIC value MUST be kept in sync with the corresponding
+    // value in the native/android/net.c NDK implementation.
+    private static final long HANDLE_MAGIC = 0xcafed00dL;
+    private static final int HANDLE_MAGIC_SIZE = 32;
 
     /**
      * @hide
@@ -137,9 +144,15 @@
             for (int i = 0; i < hostAddresses.length; i++) {
                 try {
                     Socket socket = createSocket();
-                    if (localAddress != null) socket.bind(localAddress);
-                    socket.connect(new InetSocketAddress(hostAddresses[i], port));
-                    return socket;
+                    boolean failed = true;
+                    try {
+                        if (localAddress != null) socket.bind(localAddress);
+                        socket.connect(new InetSocketAddress(hostAddresses[i], port));
+                        failed = false;
+                        return socket;
+                    } finally {
+                        if (failed) IoUtils.closeQuietly(socket);
+                    }
                 } catch (IOException e) {
                     if (i == (hostAddresses.length - 1)) throw e;
                 }
@@ -156,15 +169,27 @@
         public Socket createSocket(InetAddress address, int port, InetAddress localAddress,
                 int localPort) throws IOException {
             Socket socket = createSocket();
-            socket.bind(new InetSocketAddress(localAddress, localPort));
-            socket.connect(new InetSocketAddress(address, port));
+            boolean failed = true;
+            try {
+                socket.bind(new InetSocketAddress(localAddress, localPort));
+                socket.connect(new InetSocketAddress(address, port));
+                failed = false;
+            } finally {
+                if (failed) IoUtils.closeQuietly(socket);
+            }
             return socket;
         }
 
         @Override
         public Socket createSocket(InetAddress host, int port) throws IOException {
             Socket socket = createSocket();
-            socket.connect(new InetSocketAddress(host, port));
+            boolean failed = true;
+            try {
+                socket.connect(new InetSocketAddress(host, port));
+                failed = false;
+            } finally {
+                if (failed) IoUtils.closeQuietly(socket);
+            }
             return socket;
         }
 
@@ -176,7 +201,13 @@
         @Override
         public Socket createSocket() throws IOException {
             Socket socket = new Socket();
-            bindSocket(socket);
+            boolean failed = true;
+            try {
+                bindSocket(socket);
+                failed = false;
+            } finally {
+                if (failed) IoUtils.closeQuietly(socket);
+            }
             return socket;
         }
     }
@@ -335,6 +366,25 @@
     }
 
     /**
+     * Returns a {@link Network} object given a handle returned from {@link #getNetworkHandle}.
+     *
+     * @param networkHandle a handle returned from {@link #getNetworkHandle}.
+     * @return A {@link Network} object derived from {@code networkHandle}.
+     */
+    public static Network fromNetworkHandle(long networkHandle) {
+        if (networkHandle == 0) {
+            throw new IllegalArgumentException(
+                    "Network.fromNetworkHandle refusing to instantiate NETID_UNSET Network.");
+        }
+        if ((networkHandle & ((1L << HANDLE_MAGIC_SIZE) - 1)) != HANDLE_MAGIC
+                || networkHandle < 0) {
+            throw new IllegalArgumentException(
+                    "Value passed to fromNetworkHandle() is not a network handle.");
+        }
+        return new Network((int) (networkHandle >> HANDLE_MAGIC_SIZE));
+    }
+
+    /**
      * Returns a handle representing this {@code Network}, for use with the NDK API.
      */
     public long getNetworkHandle() {
@@ -356,14 +406,10 @@
         // At some future date it may be desirable to realign the handle with
         // Multiple Provisioning Domains API recommendations, as made by the
         // IETF mif working group.
-        //
-        // The handleMagic value MUST be kept in sync with the corresponding
-        // value in the native/android/net.c NDK implementation.
         if (netId == 0) {
             return 0L;  // make this zero condition obvious for debugging
         }
-        final long handleMagic = 0xcafed00dL;
-        return (((long) netId) << 32) | handleMagic;
+        return (((long) netId) << HANDLE_MAGIC_SIZE) | HANDLE_MAGIC;
     }
 
     // implement the Parcelable interface
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index bf20e6a..8905ad1 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -756,10 +756,15 @@
         }
         try {
             for (VolumeInfo vol : mStorageManager.getVolumes(0)) {
-                if (vol.path != null && FileUtils.contains(vol.path, pathString)) {
+                if (vol.path != null && FileUtils.contains(vol.path, pathString)
+                        && vol.type != VolumeInfo.TYPE_PUBLIC) {
                     // TODO: verify that emulated adopted devices have UUID of
                     // underlying volume
-                    return convert(vol.fsUuid);
+                    try {
+                        return convert(vol.fsUuid);
+                    } catch (IllegalArgumentException e) {
+                        continue;
+                    }
                 }
             }
         } catch (RemoteException e) {
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index 5c99f6c..9e3e386 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -312,7 +312,7 @@
      * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}.
      */
     public File getInternalPathForUser(int userId) {
-        if (type == TYPE_PUBLIC) {
+        if (type == TYPE_PUBLIC && !isVisible()) {
             // TODO: plumb through cleaner path from vold
             return new File(path.replace("/storage/", "/mnt/media_rw/"));
         } else {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b7f6cde..b0367dc 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11061,7 +11061,14 @@
          */
         public static final String LOW_POWER_MODE_TRIGGER_LEVEL_MAX = "low_power_trigger_level_max";
 
-         /**
+        /**
+         * See com.android.settingslib.fuelgauge.BatterySaverUtils.
+         * @hide
+         */
+        public static final String LOW_POWER_MODE_SUGGESTION_PARAMS =
+                "low_power_mode_suggestion_params";
+
+        /**
          * If not 0, the activity manager will aggressively finish activities and
          * processes as soon as they are no longer needed.  If 0, the normal
          * extended lifetime is used.
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index 1d13335..f4dcce1 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -75,6 +75,7 @@
     public static final int KM_TAG_ALLOW_WHILE_ON_BODY = KM_BOOL | 506;
     public static final int KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED = KM_BOOL | 507;
     public static final int KM_TAG_TRUSTED_CONFIRMATION_REQUIRED = KM_BOOL | 508;
+    public static final int KM_TAG_UNLOCKED_DEVICE_REQUIRED = KM_BOOL | 509;
 
     public static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600;
     public static final int KM_TAG_APPLICATION_ID = KM_BYTES | 601;
@@ -216,6 +217,7 @@
     public static final int KM_ERROR_MISSING_MIN_MAC_LENGTH = -58;
     public static final int KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH = -59;
     public static final int KM_ERROR_CANNOT_ATTEST_IDS = -66;
+    public static final int KM_ERROR_DEVICE_LOCKED = -72;
     public static final int KM_ERROR_UNIMPLEMENTED = -100;
     public static final int KM_ERROR_VERSION_MISMATCH = -101;
     public static final int KM_ERROR_UNKNOWN_ERROR = -1000;
@@ -262,6 +264,7 @@
         sErrorCodeToString.put(KM_ERROR_INVALID_MAC_LENGTH,
                 "Invalid MAC or authentication tag length");
         sErrorCodeToString.put(KM_ERROR_CANNOT_ATTEST_IDS, "Unable to attest device ids");
+        sErrorCodeToString.put(KM_ERROR_DEVICE_LOCKED, "Device locked");
         sErrorCodeToString.put(KM_ERROR_UNIMPLEMENTED, "Not implemented");
         sErrorCodeToString.put(KM_ERROR_UNKNOWN_ERROR, "Unknown error");
     }
diff --git a/core/java/android/security/keystore/recovery/KeyDerivationParams.java b/core/java/android/security/keystore/recovery/KeyDerivationParams.java
index d16f3ea..fd80bb0 100644
--- a/core/java/android/security/keystore/recovery/KeyDerivationParams.java
+++ b/core/java/android/security/keystore/recovery/KeyDerivationParams.java
@@ -75,7 +75,7 @@
      * Creates instance of the class to to derive keys using salted SHA256 hash.
      *
      * <p>The salted SHA256 hash is computed over the concatenation of four byte strings, salt_len +
-     * salt + key_material_len + key_material, where salt_len and key_material_len are one-byte, and
+     * salt + key_material_len + key_material, where salt_len and key_material_len are 4-byte, and
      * denote the number of bytes for salt and key_material, respectively.
      */
     public static @NonNull KeyDerivationParams createSha256Params(@NonNull byte[] salt) {
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index ab52d32..ca5f967 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -41,21 +41,133 @@
 import java.util.Map;
 
 /**
- * An assistant for generating {@link javax.crypto.SecretKey} instances that can be recovered by
- * other Android devices belonging to the user. The exported keychain is protected by the user's
- * lock screen.
+ * Backs up cryptographic keys to remote secure hardware, encrypted with the user's lock screen.
  *
- * <p>The RecoveryController must be paired with a recovery agent. The recovery agent is responsible
- * for transporting the keychain to remote trusted hardware. This hardware must prevent brute force
- * attempts against the user's lock screen by limiting the number of allowed guesses (to, e.g., 10).
- * After that number of incorrect guesses, the trusted hardware no longer allows access to the
- * key chain.
+ * <p>A system app with the {@link android.Manifest#RECOVER_KEYSTORE} permission may generate or
+ * import recoverable keys using this class. To generate a key, the app must call
+ * {@link #generateKey(String)} with the desired alias for the key. This returns an AndroidKeyStore
+ * reference to a 256-bit {@link javax.crypto.SecretKey}, which can be used for AES/GCM/NoPadding.
+ * In order to get the same key again at a later time, the app can call {@link #getKey(String)} with
+ * the same alias. If a key is generated in this way the key's raw material is never directly
+ * exposed to the calling app. The system app may also import key material using
+ * {@link #importKey(String, byte[])}. The app may only generate and import keys for its own
+ * {@code uid}.
  *
- * <p>Only the recovery agent itself is able to create keys, so it is expected that the recovery
- * agent is itself the system app.
+ * <p>The same system app must also register a Recovery Agent to manage syncing recoverable keys to
+ * remote secure hardware. The Recovery Agent is a service that registers itself with the controller
+ * as follows:
  *
- * <p>A recovery agent requires the privileged permission
- * {@code android.Manifest.permission#RECOVER_KEYSTORE}.
+ * <ul>
+ *     <li>Invokes {@link #initRecoveryService(String, byte[], byte[])}
+ *     <ul>
+ *         <li>The first argument is the alias of the root certificate used to verify trusted
+ *         hardware modules. Each trusted hardware module must have a public key signed with this
+ *         root of trust. Roots of trust must be shipped with the framework. The app can list all
+ *         valid roots of trust by calling {@link #getRootCertificates()}.
+ *         <li>The second argument is the UTF-8 bytes of the XML listing file. It lists the X509
+ *         certificates containing the public keys of all available remote trusted hardware modules.
+ *         Each of the X509 certificates can be validated against the chosen root of trust.
+ *         <li>The third argument is the UTF-8 bytes of the XML signing file. The file contains a
+ *         signature of the XML listing file. The signature can be validated against the chosen root
+ *         of trust.
+ *     </ul>
+ *     <p>This will cause the controller to choose a random public key from the list. From then
+ *     on the controller will attempt to sync the key chain with the trusted hardware module to whom
+ *     that key belongs.
+ *     <li>Invokes {@link #setServerParams(byte[])} with a byte string that identifies the device
+ *     to a remote server. This server may act as the front-end to the trusted hardware modules. It
+ *     is up to the Recovery Agent to decide how best to identify devices, but this could be, e.g.,
+ *     based on the <a href="https://developers.google.com/instance-id/">Instance ID</a> of the
+ *     system app.
+ *     <li>Invokes {@link #setRecoverySecretTypes(int[])} with a list of types of secret used to
+ *     secure the recoverable key chain. For now only
+ *     {@link KeyChainProtectionParams#TYPE_LOCKSCREEN} is supported.
+ *     <li>Invokes {@link #setSnapshotCreatedPendingIntent(PendingIntent)} with a
+ *     {@link PendingIntent} that is to be invoked whenever a new snapshot is created. Although the
+ *     controller can create snapshots without the Recovery Agent registering this intent, it is a
+ *     good idea to register the intent so that the Recovery Agent is able to sync this snapshot to
+ *     the trusted hardware module as soon as it is available.
+ * </ul>
+ *
+ * <p>The trusted hardware module's public key MUST be generated on secure hardware with protections
+ * equivalent to those described in the
+ * <a href="https://developer.android.com/preview/features/security/ckv-whitepaper.html">Google
+ * Cloud Key Vault Service whitepaper</a>. The trusted hardware module itself must protect the key
+ * chain from brute-forcing using the methods also described in the whitepaper: i.e., it should
+ * limit the number of allowed attempts to enter the lock screen. If the number of attempts is
+ * exceeded the key material must no longer be recoverable.
+ *
+ * <p>A recoverable key chain snapshot is considered pending if any of the following conditions
+ * are met:
+ *
+ * <ul>
+ *     <li>The system app mutates the key chain. i.e., generates, imports, or removes a key.
+ *     <li>The user changes their lock screen.
+ * </ul>
+ *
+ * <p>Whenever the user unlocks their device, if a snapshot is pending, the Recovery Controller
+ * generates a new snapshot. It follows these steps to do so:
+ *
+ * <ul>
+ *     <li>Generates a 256-bit AES key using {@link java.security.SecureRandom}. This is the
+ *     Recovery Key.
+ *     <li>Wraps the key material of all keys in the recoverable key chain with the Recovery Key.
+ *     <li>Encrypts the Recovery Key with both the public key of the trusted hardware module and a
+ *     symmetric key derived from the user's lock screen.
+ * </ul>
+ *
+ * <p>The controller then writes this snapshot to disk, and uses the {@link PendingIntent} that was
+ * set by the Recovery Agent during initialization to inform it that a new snapshot is available.
+ * The snapshot only contains keys for that Recovery Agent's {@code uid} - i.e., keys the agent's
+ * app itself generated. If multiple Recovery Agents exist on the device, each will be notified of
+ * their new snapshots, and each snapshots' keys will be only those belonging to the same
+ * {@code uid}.
+ *
+ * <p>The Recovery Agent retrieves its most recent snapshot by calling
+ * {@link #getKeyChainSnapshot()}. It syncs the snapshot to the remote server. The snapshot contains
+ * the public key used for encryption, which the server uses to forward the encrypted recovery key
+ * to the correct trusted hardware module. The snapshot also contains the server params, which are
+ * used to identify this device to the server.
+ *
+ * <p>The client uses the server params to identify a device whose key chain it wishes to restore.
+ * This may be on a different device to the device that originally synced the key chain. The client
+ * sends the server params identifying the previous device to the server. The server returns the
+ * X509 certificate identifying the trusted hardware module in which the encrypted Recovery Key is
+ * stored. It also returns some vault parameters identifying that particular Recovery Key to the
+ * trusted hardware module. And it also returns a vault challenge, which is used as part of the
+ * vault opening protocol to ensure the recovery claim is fresh. See the whitepaper for more
+ * details.
+ *
+ * <p>The key chain is recovered via a {@link RecoverySession}. A Recovery Agent creates one by
+ * invoking {@link #createRecoverySession()}. It then invokes
+ * {@link RecoverySession#start(String, CertPath, byte[], byte[], List)} with these arguments:
+ *
+ * <ul>
+ *     <li>The alias of the root of trust used to verify the trusted hardware module.
+ *     <li>The X509 certificate of the trusted hardware module.
+ *     <li>The vault parameters used to identify the Recovery Key to the trusted hardware module.
+ *     <li>The vault challenge, as issued by the trusted hardware module.
+ *     <li>A list of secrets, corresponding to the secrets used to protect the key chain. At the
+ *     moment this is a single {@link KeyChainProtectionParams} containing the lock screen of the
+ *     device whose key chain is to be recovered.
+ * </ul>
+ *
+ * <p>This method returns a byte array containing the Recovery Claim, which can be issued to the
+ * remote trusted hardware module. It is encrypted with the trusted hardware module's public key
+ * (which has itself been certified with the root of trust). It also contains an ephemeral symmetric
+ * key generated for this recovery session, which the remote trusted hardware module uses to encrypt
+ * its responses. This is the Session Key.
+ *
+ * <p>If the lock screen provided is correct, the remote trusted hardware module decrypts one of the
+ * layers of lock-screen encryption from the Recovery Key. It then returns this key, encrypted with
+ * the Session Key to the Recovery Agent. As the Recovery Agent does not know the Session Key, it
+ * must then invoke {@link RecoverySession#recoverKeyChainSnapshot(byte[], List)} with the encrypted
+ * Recovery Key and the list of wrapped application keys. The controller then decrypts the layer of
+ * encryption provided by the Session Key, and uses the lock screen to decrypt the final layer of
+ * encryption. It then uses the Recovery Key to decrypt all of the wrapped application keys, and
+ * imports them into its own KeyStore. The Recovery Agent's app may then access these keys by
+ * calling {@link #getKey(String)}. Only this app's {@code uid} may access the keys that have been
+ * recovered.
  *
  * @hide
  */
diff --git a/core/java/android/security/keystore/recovery/TrustedRootCertificates.java b/core/java/android/security/keystore/recovery/TrustedRootCertificates.java
index 383af42..63faac3 100644
--- a/core/java/android/security/keystore/recovery/TrustedRootCertificates.java
+++ b/core/java/android/security/keystore/recovery/TrustedRootCertificates.java
@@ -37,6 +37,40 @@
 
     public static final String GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS =
             "GoogleCloudKeyVaultServiceV1";
+    /**
+     * Certificate used for client-side end-to-end encryption tests.
+     * When recovery controller is initialized with the certificate, recovery snapshots will only
+     * contain application keys started with {@link INSECURE_KEY_ALIAS}.
+     * Recovery snapshot will only be created if device is unlocked with password started with
+     * {@link #INSECURE_PASSWORD_PREFIX}.
+     *
+     * @hide
+     */
+    public static final String TEST_ONLY_INSECURE_CERTIFICATE_ALIAS =
+            "TEST_ONLY_INSECURE_CERTIFICATE_ALIAS";
+
+    /**
+     * TODO: Add insecure certificate to TestApi.
+     * @hide
+     */
+    public static @NonNull X509Certificate getTestOnlyInsecureCertificate() {
+        return parseBase64Certificate(TEST_ONLY_INSECURE_CERTIFICATE_BASE64);
+    }
+    /**
+     * Keys, which alias starts with the prefix are not protected if
+     * recovery agent uses {@link #TEST_ONLY_INSECURE_CERTIFICATE_ALIAS} root certificate.
+     * @hide
+     */
+    public static final String INSECURE_KEY_ALIAS_PREFIX =
+            "INSECURE_KEY_ALIAS_KEY_MATERIAL_IS_NOT_PROTECTED_";
+    /**
+     * Prefix for insecure passwords with length 14.
+     * Passwords started with the prefix are not protected if recovery agent uses
+     * {@link #TEST_ONLY_INSECURE_CERTIFICATE_ALIAS} root certificate.
+     * @hide
+     */
+    public static final String INSECURE_PASSWORD_PREFIX =
+            "INSECURE_PSWD_";
 
     private static final String GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_BASE64 = ""
             + "MIIFJjCCAw6gAwIBAgIJAIobXsJlzhNdMA0GCSqGSIb3DQEBDQUAMCAxHjAcBgNV"
@@ -68,13 +102,43 @@
             + "/oM58v0orUWINtIc2hBlka36PhATYQiLf+AiWKnwhCaaHExoYKfQlMtXBodNvOK8"
             + "xqx69x05q/qbHKEcTHrsss630vxrp1niXvA=";
 
+    private static final String TEST_ONLY_INSECURE_CERTIFICATE_BASE64 = ""
+            + "MIIFMDCCAxigAwIBAgIJAIZ9/G8KQie9MA0GCSqGSIb3DQEBDQUAMCUxIzAhBgNV"
+            + "BAMMGlRlc3QgT25seSBVbnNlY3VyZSBSb290IENBMB4XDTE4MDMyODAwMzIyM1oX"
+            + "DTM4MDMyMzAwMzIyM1owJTEjMCEGA1UEAwwaVGVzdCBPbmx5IFVuc2VjdXJlIFJv"
+            + "b3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDGxFNzAEyzSPmw"
+            + "E5gfuBXdXq++bl9Ep62V7Xn1UiejvmS+pRHT39pf/M7sl4Zr9ezanJTrFvf9+B85"
+            + "VGehdsD32TgfEjThcqaoQCI6pKkHYsUo7FZ5n+G3eE8oabWRZJMVo3QDjnnFYp7z"
+            + "20vnpjDofI2oQyxHcb/1yep+ca1+4lIvbUp/ybhNFqhRXAMcDXo7pyH38eUQ1JdK"
+            + "Q/QlBbShpFEqx1Y6KilKfTDf7Wenqr67LkaEim//yLZjlHzn/BpuRTrpo+XmJZx1"
+            + "P9CX9LGOXTtmsaCcYgD4yijOvV8aEsIJaf1kCIO558oH0oQc+0JG5aXeLN7BDlyZ"
+            + "vH0RdSx5nQLS9kj2I6nthOw/q00/L+S6A0m5jyNZOAl1SY78p+wO0d9eHbqQzJwf"
+            + "EsSq3qGAqlgQyyjp6oxHBqT9hZtN4rxw+iq0K1S4kmTLNF1FvmIB1BE+lNvvoGdY"
+            + "5G0b6Pe4R5JFn9LV3C3PEmSYnae7iG0IQlKmRADIuvfJ7apWAVanJPJAAWh2Akfp"
+            + "8Uxr02cHoY6o7vsEhJJOeMkipaBHThESm/XeFVubQzNfZ9gjQnB9ZX2v+lyj+WYZ"
+            + "SAz3RuXx6TlLrmWccMpQDR1ibcgyyjLUtX3kwZl2OxmJXitjuD7xlxvAXYob15N+"
+            + "K4xKHgxUDrbt2zU/tY0vgepAUg/xbwIDAQABo2MwYTAdBgNVHQ4EFgQUwyeNpYgs"
+            + "XXYvh9z0/lFrja7sV+swHwYDVR0jBBgwFoAUwyeNpYgsXXYvh9z0/lFrja7sV+sw"
+            + "DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQENBQAD"
+            + "ggIBAGuOsvMN5SD3RIQnMJtBpcHNrxun+QFjPZFlYCLfIPrUkHpn5O1iIIq8tVLd"
+            + "2V+12VKnToUEANsYBD3MP8XjP+6GZ7ZQ2rwLGvUABKSX4YXvmjEEXZUZp0y3tIV4"
+            + "kUDlbACzguPneZDp5Qo7YWH4orgqzHkn0sD/ikO5XrAqmzc245ewJlrf+V11mjcu"
+            + "ELfDrEejpPhi7Hk/ZNR0ftP737Hs/dNoCLCIaVNgYzBZhgo4kd220TeJu2ttW0XZ"
+            + "ldyShtpcOmyWKBgVseixR6L/3sspPHyAPXkSuRo0Eh1xvzDKCg9ttb0qoacTlXMF"
+            + "GkBpNzmVq67NWFGGa9UElift1mv6RfktPCAGZ+Ai8xUiKAUB0Eookpt/8gX9Senq"
+            + "yP/jMxkxXmHWxUu8+KnLvj6WLrfftuuD7u3cfc7j5kkrheDz3O4h4477GnqL5wdo"
+            + "9DuEsNc4FxJVz8Iy8RS6cJuW4pihYpM1Tyn7uopLnImpYzEY+R5aQqqr+q/A1diq"
+            + "ogbEKPH6oUiqJUwq3nD70gPBUKJmIzS4vLwLouqUHEm1k/MgHV/BkEU0uVHszPFa"
+            + "XUMMCHb0iT9P8LuZ7Ajer3SR/0TRVApCrk/6OV68e+6k/OFpM5kcZnNMD5ANyBri"
+            + "Tsz3NrDwSw4i4+Dsfh6A9dB/cEghw4skLaBxnQLQIgVeqCzK";
+
     /**
      * The X509 certificate of the trusted root CA cert for the recoverable key store service.
      *
      * TODO: Change it to the production certificate root CA before the final launch.
      */
     private static final X509Certificate GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_CERTIFICATE =
-            parseGoogleCloudKeyVaultServiceV1Certificate();
+            parseBase64Certificate(GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_BASE64);
 
     private static final int NUMBER_OF_ROOT_CERTIFICATES = 1;
 
@@ -107,9 +171,9 @@
         return certificates;
     }
 
-    private static X509Certificate parseGoogleCloudKeyVaultServiceV1Certificate() {
+    private static X509Certificate parseBase64Certificate(String base64Certificate) {
         try {
-            return decodeBase64Cert(GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_BASE64);
+            return decodeBase64Cert(base64Certificate);
         } catch (CertificateException e) {
             // Should not happen
             throw new RuntimeException(e);
diff --git a/core/java/android/service/autofill/AutofillFieldClassificationService.java b/core/java/android/service/autofill/AutofillFieldClassificationService.java
index 99d45f4..1cd76d2 100644
--- a/core/java/android/service/autofill/AutofillFieldClassificationService.java
+++ b/core/java/android/service/autofill/AutofillFieldClassificationService.java
@@ -41,11 +41,11 @@
  *
  * <p>A field classification score is a {@code float} representing how well an
  * {@link AutofillValue} filled matches a expected value predicted by an autofill service
- * &mdash;a full-match is {@code 1.0} (representing 100%), while a full mismatch is {@code 0.0}.
+ * &mdash;a full match is {@code 1.0} (representing 100%), while a full mismatch is {@code 0.0}.
  *
- * <p>The exact score depends on the algorithm used to calculate it&mdash; the service must provide
+ * <p>The exact score depends on the algorithm used to calculate it&mdash;the service must provide
  * at least one default algorithm (which is used when the algorithm is not specified or is invalid),
- * but it could provide more (in which case the algorithm name should be specifiied by the caller
+ * but it could provide more (in which case the algorithm name should be specified by the caller
  * when calculating the scores).
  *
  * {@hide}
@@ -115,15 +115,15 @@
      *
      * <p>A field classification score is a {@code float} representing how well an
      * {@link AutofillValue} filled matches a expected value predicted by an autofill service
-     * &mdash;a full-match is {@code 1.0} (representing 100%), while a full mismatch is {@code 0.0}.
+     * &mdash;a full match is {@code 1.0} (representing 100%), while a full mismatch is {@code 0.0}.
      *
-     * <p>The exact score depends on the algorithm used to calculate it&mdash; the service must
+     * <p>The exact score depends on the algorithm used to calculate it&mdash;the service must
      * provide at least one default algorithm (which is used when the algorithm is not specified
      * or is invalid), but it could provide more (in which case the algorithm name should be
-     * specifiied by the caller when calculating the scores).
+     * specified by the caller when calculating the scores).
      *
      * <p>For example, if the service provides an algorithm named {@code EXACT_MATCH} that
-     * returns {@code 1.0} if all characters in match or {@code 0.0} otherwise, a call to:
+     * returns {@code 1.0} if all characters match or {@code 0.0} otherwise, a call to:
      *
      * <pre>
      * service.onGetScores("EXACT_MATCH", null,
diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java
index df62446..6e5bacf 100644
--- a/core/java/android/service/autofill/FillEventHistory.java
+++ b/core/java/android/service/autofill/FillEventHistory.java
@@ -424,7 +424,7 @@
          * @return map map whose key is the id of the manually-entered field, and value is the
          * ids of the datasets that have that value but were not selected by the user.
          */
-        @Nullable public Map<AutofillId, Set<String>> getManuallyEnteredField() {
+        @NonNull public Map<AutofillId, Set<String>> getManuallyEnteredField() {
             if (mManuallyFilledFieldIds == null || mManuallyFilledDatasetIds == null) {
                 return Collections.emptyMap();
             }
diff --git a/core/java/android/service/notification/ScheduleCalendar.java b/core/java/android/service/notification/ScheduleCalendar.java
index 8a7ff4d..0128710 100644
--- a/core/java/android/service/notification/ScheduleCalendar.java
+++ b/core/java/android/service/notification/ScheduleCalendar.java
@@ -144,7 +144,8 @@
         }
         return mSchedule.exitAtAlarm
                 && mSchedule.nextAlarm != 0
-                && time >= mSchedule.nextAlarm;
+                && time >= mSchedule.nextAlarm
+                && isInSchedule(mSchedule.nextAlarm);
     }
 
     private boolean isInSchedule(int daysOffset, long time, long start, long end) {
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 630007b..b413d48 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -43,8 +43,8 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.time.ZonedDateTime;
 import java.util.ArrayList;
-import java.util.Calendar;
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
@@ -512,7 +512,7 @@
     public static final class Options implements Parcelable {
 
         private @Nullable LocaleList mDefaultLocales;
-        private @Nullable Calendar mReferenceTime;
+        private @Nullable ZonedDateTime mReferenceTime;
 
         public Options() {}
 
@@ -531,7 +531,7 @@
          *      be interpreted. This should usually be the time when the text was originally
          *      composed. If no reference time is set, now is used.
          */
-        public Options setReferenceTime(Calendar referenceTime) {
+        public Options setReferenceTime(ZonedDateTime referenceTime) {
             mReferenceTime = referenceTime;
             return this;
         }
@@ -550,7 +550,7 @@
          *      interpreted.
          */
         @Nullable
-        public Calendar getReferenceTime() {
+        public ZonedDateTime getReferenceTime() {
             return mReferenceTime;
         }
 
@@ -567,7 +567,7 @@
             }
             dest.writeInt(mReferenceTime != null ? 1 : 0);
             if (mReferenceTime != null) {
-                dest.writeSerializable(mReferenceTime);
+                dest.writeString(mReferenceTime.toString());
             }
         }
 
@@ -589,7 +589,7 @@
                 mDefaultLocales = LocaleList.CREATOR.createFromParcel(in);
             }
             if (in.readInt() > 0) {
-                mReferenceTime = (Calendar) in.readSerializable();
+                mReferenceTime = ZonedDateTime.parse(in.readString());
             }
         }
     }
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 5ba470a..8d1ed0e 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -16,6 +16,8 @@
 
 package android.view.textclassifier;
 
+import static java.time.temporal.ChronoUnit.MILLIS;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.WorkerThread;
@@ -45,9 +47,10 @@
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
+import java.time.Instant;
+import java.time.ZonedDateTime;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Calendar;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -119,7 +122,7 @@
                     && rangeLength <= mSettings.getSuggestSelectionMaxRangeLength()) {
                 final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
                 final String localesString = concatenateLocales(locales);
-                final Calendar refTime = Calendar.getInstance();
+                final ZonedDateTime refTime = ZonedDateTime.now();
                 final boolean darkLaunchAllowed = options != null && options.isDarkLaunchAllowed();
                 final TextClassifierImplNative nativeImpl = getNative(locales);
                 final String string = text.toString();
@@ -143,8 +146,8 @@
                             nativeImpl.classifyText(
                                     string, start, end,
                                     new TextClassifierImplNative.ClassificationOptions(
-                                            refTime.getTimeInMillis(),
-                                            refTime.getTimeZone().getID(),
+                                            refTime.toInstant().toEpochMilli(),
+                                            refTime.getZone().getId(),
                                             localesString));
                     final int size = results.length;
                     for (int i = 0; i < size; i++) {
@@ -183,19 +186,20 @@
                 final String string = text.toString();
                 final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
                 final String localesString = concatenateLocales(locales);
-                final Calendar refTime = (options != null && options.getReferenceTime() != null)
-                        ? options.getReferenceTime() : Calendar.getInstance();
+                final ZonedDateTime refTime =
+                        (options != null && options.getReferenceTime() != null)
+                                ? options.getReferenceTime() : ZonedDateTime.now();
 
                 final TextClassifierImplNative.ClassificationResult[] results =
                         getNative(locales)
                                 .classifyText(string, startIndex, endIndex,
                                         new TextClassifierImplNative.ClassificationOptions(
-                                                refTime.getTimeInMillis(),
-                                                refTime.getTimeZone().getID(),
+                                                refTime.toInstant().toEpochMilli(),
+                                                refTime.getZone().getId(),
                                                 localesString));
                 if (results.length > 0) {
                     return createClassificationResult(
-                            results, string, startIndex, endIndex, refTime);
+                            results, string, startIndex, endIndex, refTime.toInstant());
                 }
             }
         } catch (Throwable t) {
@@ -224,7 +228,7 @@
         try {
             final long startTimeMs = System.currentTimeMillis();
             final LocaleList defaultLocales = options != null ? options.getDefaultLocales() : null;
-            final Calendar refTime = Calendar.getInstance();
+            final ZonedDateTime refTime = ZonedDateTime.now();
             final Collection<String> entitiesToIdentify =
                     options != null && options.getEntityConfig() != null
                             ? options.getEntityConfig().resolveEntityListModifications(
@@ -236,8 +240,8 @@
                     nativeImpl.annotate(
                         textString,
                         new TextClassifierImplNative.AnnotationOptions(
-                                refTime.getTimeInMillis(),
-                                refTime.getTimeZone().getID(),
+                                refTime.toInstant().toEpochMilli(),
+                                refTime.getZone().getId(),
                                 concatenateLocales(defaultLocales)));
             for (TextClassifierImplNative.AnnotatedSpan span : annotations) {
                 final TextClassifierImplNative.ClassificationResult[] results =
@@ -416,7 +420,7 @@
 
     private TextClassification createClassificationResult(
             TextClassifierImplNative.ClassificationResult[] classifications,
-            String text, int start, int end, @Nullable Calendar referenceTime) {
+            String text, int start, int end, @Nullable Instant referenceTime) {
         final String classifiedText = text.substring(start, end);
         final TextClassification.Builder builder = new TextClassification.Builder()
                 .setText(classifiedText);
@@ -646,7 +650,7 @@
         @NonNull
         public static List<LabeledIntent> create(
                 Context context,
-                @Nullable Calendar referenceTime,
+                @Nullable Instant referenceTime,
                 TextClassifierImplNative.ClassificationResult classification,
                 String text) {
             final String type = classification.getCollection().trim().toLowerCase(Locale.ENGLISH);
@@ -663,10 +667,9 @@
                 case TextClassifier.TYPE_DATE:
                 case TextClassifier.TYPE_DATE_TIME:
                     if (classification.getDatetimeResult() != null) {
-                        Calendar eventTime = Calendar.getInstance();
-                        eventTime.setTimeInMillis(
+                        final Instant parsedTime = Instant.ofEpochMilli(
                                 classification.getDatetimeResult().getTimeMsUtc());
-                        return createForDatetime(context, type, referenceTime, eventTime);
+                        return createForDatetime(context, type, referenceTime, parsedTime);
                     } else {
                         return new ArrayList<>();
                     }
@@ -758,18 +761,17 @@
 
         @NonNull
         private static List<LabeledIntent> createForDatetime(
-                Context context, String type, @Nullable Calendar referenceTime,
-                Calendar eventTime) {
+                Context context, String type, @Nullable Instant referenceTime,
+                Instant parsedTime) {
             if (referenceTime == null) {
                 // If no reference time was given, use now.
-                referenceTime = Calendar.getInstance();
+                referenceTime = Instant.now();
             }
             List<LabeledIntent> actions = new ArrayList<>();
-            actions.add(createCalendarViewIntent(context, eventTime));
-            final long millisSinceReference =
-                    eventTime.getTimeInMillis() - referenceTime.getTimeInMillis();
-            if (millisSinceReference > MIN_EVENT_FUTURE_MILLIS) {
-                actions.add(createCalendarCreateEventIntent(context, eventTime, type));
+            actions.add(createCalendarViewIntent(context, parsedTime));
+            final long millisUntilEvent = referenceTime.until(parsedTime, MILLIS);
+            if (millisUntilEvent > MIN_EVENT_FUTURE_MILLIS) {
+                actions.add(createCalendarCreateEventIntent(context, parsedTime, type));
             }
             return actions;
         }
@@ -784,10 +786,10 @@
         }
 
         @NonNull
-        private static LabeledIntent createCalendarViewIntent(Context context, Calendar eventTime) {
+        private static LabeledIntent createCalendarViewIntent(Context context, Instant parsedTime) {
             Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon();
             builder.appendPath("time");
-            ContentUris.appendId(builder, eventTime.getTimeInMillis());
+            ContentUris.appendId(builder, parsedTime.toEpochMilli());
             return new LabeledIntent(
                     context.getString(com.android.internal.R.string.view_calendar),
                     context.getString(com.android.internal.R.string.view_calendar_desc),
@@ -796,7 +798,7 @@
 
         @NonNull
         private static LabeledIntent createCalendarCreateEventIntent(
-                Context context, Calendar eventTime, @EntityType String type) {
+                Context context, Instant parsedTime, @EntityType String type) {
             final boolean isAllDay = TextClassifier.TYPE_DATE.equals(type);
             return new LabeledIntent(
                     context.getString(com.android.internal.R.string.add_calendar_event),
@@ -805,9 +807,9 @@
                             .setData(CalendarContract.Events.CONTENT_URI)
                             .putExtra(CalendarContract.EXTRA_EVENT_ALL_DAY, isAllDay)
                             .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME,
-                                    eventTime.getTimeInMillis())
+                                    parsedTime.toEpochMilli())
                             .putExtra(CalendarContract.EXTRA_EVENT_END_TIME,
-                                    eventTime.getTimeInMillis() + DEFAULT_EVENT_DURATION));
+                                    parsedTime.toEpochMilli() + DEFAULT_EVENT_DURATION));
         }
     }
 }
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 92f496a8..9946726 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -4585,8 +4585,8 @@
             return mContainer.isShowing();
         }
 
-        private boolean isVisible() {
-            // Always show a dragging handle.
+        private boolean shouldShow() {
+            // A dragging handle should always be shown.
             if (mIsDragging) {
                 return true;
             }
@@ -4599,6 +4599,10 @@
                     mPositionX + mHotspotX + getHorizontalOffset(), mPositionY);
         }
 
+        private void setVisible(final boolean visible) {
+            mContainer.getContentView().setVisibility(visible ? VISIBLE : INVISIBLE);
+        }
+
         public abstract int getCurrentCursorOffset();
 
         protected abstract void updateSelection(int offset);
@@ -4692,7 +4696,7 @@
                     onHandleMoved();
                 }
 
-                if (isVisible()) {
+                if (shouldShow()) {
                     // Transform to the window coordinates to follow the view tranformation.
                     final int[] pts = { mPositionX + mHotspotX + getHorizontalOffset(), mPositionY};
                     mTextView.transformFromViewToWindowSpace(pts);
@@ -4745,6 +4749,15 @@
             return 0;
         }
 
+        private boolean tooLargeTextForMagnifier() {
+            final float magnifierContentHeight = Math.round(
+                    mMagnifierAnimator.mMagnifier.getHeight()
+                            / mMagnifierAnimator.mMagnifier.getZoom());
+            final Paint.FontMetrics fontMetrics = mTextView.getPaint().getFontMetrics();
+            final float glyphHeight = fontMetrics.descent - fontMetrics.ascent;
+            return glyphHeight > magnifierContentHeight;
+        }
+
         /**
          * Computes the position where the magnifier should be shown, relative to
          * {@code mTextView}, and writes them to {@code showPosInView}. Also decides
@@ -4824,13 +4837,12 @@
             return true;
         }
 
-        private boolean tooLargeTextForMagnifier() {
-            final float magnifierContentHeight = Math.round(
-                    mMagnifierAnimator.mMagnifier.getHeight()
-                            / mMagnifierAnimator.mMagnifier.getZoom());
-            final Paint.FontMetrics fontMetrics = mTextView.getPaint().getFontMetrics();
-            final float glyphHeight = fontMetrics.descent - fontMetrics.ascent;
-            return glyphHeight > magnifierContentHeight;
+        private boolean handleOverlapsMagnifier() {
+            final int handleY = mContainer.getDecorViewLayoutParams().y;
+            final int magnifierBottomWhenAtWindowTop =
+                    mTextView.getRootWindowInsets().getSystemWindowInsetTop()
+                        + mMagnifierAnimator.mMagnifier.getHeight();
+            return handleY <= magnifierBottomWhenAtWindowTop;
         }
 
         protected final void updateMagnifier(@NonNull final MotionEvent event) {
@@ -4846,6 +4858,13 @@
                 mRenderCursorRegardlessTiming = true;
                 mTextView.invalidateCursorPath();
                 suspendBlink();
+                // Hide handle if it overlaps the magnifier.
+                if (handleOverlapsMagnifier()) {
+                    setVisible(false);
+                } else {
+                    setVisible(true);
+                }
+
                 mMagnifierAnimator.show(showPosInView.x, showPosInView.y);
             } else {
                 dismissMagnifier();
@@ -4857,6 +4876,7 @@
                 mMagnifierAnimator.dismiss();
                 mRenderCursorRegardlessTiming = false;
                 resumeBlink();
+                setVisible(true);
             }
         }
 
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 957c784..51dd929 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -1008,9 +1008,6 @@
                 mDrawingProfilingStarted = false;
             }
         }
-        if (mFadePattern) {
-            clearPattern();
-        }
     }
 
     private void cancelLineAnimations() {
diff --git a/core/jni/android/graphics/ImageDecoder.cpp b/core/jni/android/graphics/ImageDecoder.cpp
index 726c450..825b7a0 100644
--- a/core/jni/android/graphics/ImageDecoder.cpp
+++ b/core/jni/android/graphics/ImageDecoder.cpp
@@ -210,7 +210,7 @@
                                           jint desiredWidth, jint desiredHeight, jobject jsubset,
                                           jboolean requireMutable, jint allocator,
                                           jboolean requireUnpremul, jboolean preferRamOverQuality,
-                                          jboolean asAlphaMask) {
+                                          jboolean asAlphaMask, jobject jcolorSpace) {
     auto* decoder = reinterpret_cast<ImageDecoder*>(nativePtr);
     SkAndroidCodec* codec = decoder->mCodec.get();
     const SkISize desiredSize = SkISize::Make(desiredWidth, desiredHeight);
@@ -264,7 +264,8 @@
         // This is currently the only way to know that we should decode to F16.
         colorType = codec->computeOutputColorType(colorType);
     }
-    sk_sp<SkColorSpace> colorSpace = codec->computeOutputColorSpace(colorType);
+    sk_sp<SkColorSpace> colorSpace = GraphicsJNI::getNativeColorSpace(env, jcolorSpace);
+    colorSpace = codec->computeOutputColorSpace(colorType, colorSpace);
     decodeInfo = decodeInfo.makeColorType(colorType).makeColorSpace(colorSpace);
 
     SkBitmap bm;
@@ -507,18 +508,26 @@
     return encodedFormatToString(env, decoder->mCodec->getEncodedFormat());
 }
 
+static jobject ImageDecoder_nGetColorSpace(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
+    auto* codec = reinterpret_cast<ImageDecoder*>(nativePtr)->mCodec.get();
+    auto colorType = codec->computeOutputColorType(codec->getInfo().colorType());
+    sk_sp<SkColorSpace> colorSpace = codec->computeOutputColorSpace(colorType);
+    return GraphicsJNI::getColorSpace(env, colorSpace, colorType);
+}
+
 static const JNINativeMethod gImageDecoderMethods[] = {
     { "nCreate",        "(JLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;",    (void*) ImageDecoder_nCreateAsset },
     { "nCreate",        "(Ljava/nio/ByteBuffer;IILandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteBuffer },
     { "nCreate",        "([BIILandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
     { "nCreate",        "(Ljava/io/InputStream;[BLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
     { "nCreate",        "(Ljava/io/FileDescriptor;Landroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
-    { "nDecodeBitmap",  "(JLandroid/graphics/ImageDecoder;ZIILandroid/graphics/Rect;ZIZZZ)Landroid/graphics/Bitmap;",
+    { "nDecodeBitmap",  "(JLandroid/graphics/ImageDecoder;ZIILandroid/graphics/Rect;ZIZZZLandroid/graphics/ColorSpace;)Landroid/graphics/Bitmap;",
                                                                  (void*) ImageDecoder_nDecodeBitmap },
     { "nGetSampledSize","(JI)Landroid/util/Size;",               (void*) ImageDecoder_nGetSampledSize },
     { "nGetPadding",    "(JLandroid/graphics/Rect;)V",           (void*) ImageDecoder_nGetPadding },
     { "nClose",         "(J)V",                                  (void*) ImageDecoder_nClose},
     { "nGetMimeType",   "(J)Ljava/lang/String;",                 (void*) ImageDecoder_nGetMimeType },
+    { "nGetColorSpace", "(J)Landroid/graphics/ColorSpace;",      (void*) ImageDecoder_nGetColorSpace },
 };
 
 int register_android_graphics_ImageDecoder(JNIEnv* env) {
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 04cb08f..b0f68cd 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -37,7 +37,7 @@
 #include <system/graphics.h>
 #include <ui/DisplayInfo.h>
 #include <ui/FrameStats.h>
-#include <ui/GraphicsTypes.h>
+#include <ui/GraphicTypes.h>
 #include <ui/HdrCapabilities.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
@@ -598,7 +598,7 @@
 static jintArray nativeGetDisplayColorModes(JNIEnv* env, jclass, jobject tokenObj) {
     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
     if (token == NULL) return NULL;
-    Vector<ColorMode> colorModes;
+    Vector<ui::ColorMode> colorModes;
     if (SurfaceComposerClient::getDisplayColorModes(token, &colorModes) != NO_ERROR ||
             colorModes.isEmpty()) {
         return NULL;
@@ -628,7 +628,7 @@
     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
     if (token == NULL) return JNI_FALSE;
     status_t err = SurfaceComposerClient::setActiveColorMode(token,
-            static_cast<ColorMode>(colorMode));
+            static_cast<ui::ColorMode>(colorMode));
     return err == NO_ERROR ? JNI_TRUE : JNI_FALSE;
 }
 
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index b5fd792..b2853c9 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -260,7 +260,7 @@
   }
 
   // Apply system or app filter based on uid.
-  if (getuid() >= AID_APP_START) {
+  if (uid >= AID_APP_START) {
     set_app_seccomp_filter();
   } else {
     set_system_seccomp_filter();
@@ -619,11 +619,6 @@
       fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
     }
 
-    // Must be called when the new process still has CAP_SYS_ADMIN.  The other alternative is to
-    // call prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that breaks SELinux domain transition (see
-    // b/71859146).
-    SetUpSeccompFilter(uid);
-
     // Keep capabilities across UID change, unless we're staying root.
     if (uid != 0) {
       if (!EnableKeepCapabilities(&error_msg)) {
@@ -699,6 +694,13 @@
       fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno)));
     }
 
+    // Must be called when the new process still has CAP_SYS_ADMIN, in this case, before changing
+    // uid from 0, which clears capabilities.  The other alternative is to call
+    // prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that breaks SELinux domain transition (see
+    // b/71859146).  As the result, privileged syscalls used below still need to be accessible in
+    // app process.
+    SetUpSeccompFilter(uid);
+
     rc = setresuid(uid, uid, uid);
     if (rc == -1) {
       fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno)));
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 0fea0dc..ea0b825 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -175,9 +175,9 @@
     ];
 
     optional GZippedFileProto last_kmsg = 2007 [
-        (section).type = SECTION_NONE, // disable until selinux permission is gained
+        (section).type = SECTION_GZIP,
         (section).args = "/sys/fs/pstore/console-ramoops /sys/fs/pstore/console-ramoops-0 /proc/last_kmsg",
-        (privacy).dest = DEST_AUTOMATIC
+        (privacy).dest = DEST_EXPLICIT
     ];
 
     // System Services
diff --git a/core/proto/android/os/system_properties.proto b/core/proto/android/os/system_properties.proto
index 694b94b..8bf3772 100644
--- a/core/proto/android/os/system_properties.proto
+++ b/core/proto/android/os/system_properties.proto
@@ -192,6 +192,8 @@
     optional string libc_debug_malloc_program = 15;
 
     message Log {
+        option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional string tag_WifiHAL = 1;
         optional string tag_stats_log = 2;
 
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index c7de947..b5303c8 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -672,8 +672,10 @@
         option (android.msg_privacy).dest = DEST_LOCAL;
 
         // The requested Private DNS mode and an accompanying specifier.
-        optional SettingProto dns_mode = 1;
-        optional SettingProto dns_specifier = 2;
+        // msg_privacy settings don't apply to sub messages, only to primitive
+        // fields, so these must also be explicitly set to LOCAL.
+        optional SettingProto dns_mode = 1 [ (android.privacy).dest = DEST_LOCAL ];
+        optional SettingProto dns_specifier = 2 [ (android.privacy).dest = DEST_LOCAL ];
     }
     optional Private private = 96;
 
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index bb8ce81..4df3b63 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -527,9 +527,7 @@
     optional int32 calling_uid = 1;
     // Job IDs can technically be negative.
     optional int32 job_id = 2;
-    optional string battery_name = 3 [
-        (.android.privacy).dest = DEST_EXPLICIT
-    ];
+    optional string battery_name = 3;
 }
 
 // Dump from a com.android.server.job.controllers.JobStatus object.
diff --git a/core/proto/android/service/usb.proto b/core/proto/android/service/usb.proto
index b60c569..8240d8a 100644
--- a/core/proto/android/service/usb.proto
+++ b/core/proto/android/service/usb.proto
@@ -80,7 +80,7 @@
     optional string model = 2;
     optional string description = 3;
     optional string version = 4;
-    optional string uri = 5;
+    optional string uri = 5 [ (android.privacy).dest = DEST_EXPLICIT ];
     optional string serial = 6 [ (android.privacy).dest = DEST_EXPLICIT ];
 }
 
@@ -155,6 +155,7 @@
 message UsbConnectionRecordProto {
     option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
+    // usb device's address, e.g. 001/002, nothing about the phone
     optional string device_address = 1;
     optional android.service.UsbConnectionRecordMode mode = 2;
     optional int64 timestamp = 3;
@@ -251,6 +252,7 @@
     optional string name = 3;
     optional bool has_playback = 4;
     optional bool has_capture = 5;
+    // usb device's address, e.g. 001/002, nothing about the phone
     optional string address = 6;
 }
 
@@ -259,6 +261,7 @@
 
     optional int32 card = 1;
     optional int32 device = 2;
+    // usb device's address, e.g. 001/002, nothing about the phone
     optional string device_address = 3;
 }
 
diff --git a/core/proto/android/view/displayinfo.proto b/core/proto/android/view/displayinfo.proto
index cbd06fd..2a03050 100644
--- a/core/proto/android/view/displayinfo.proto
+++ b/core/proto/android/view/displayinfo.proto
@@ -29,5 +29,5 @@
   optional int32 logical_height = 2;
   optional int32 app_width = 3;
   optional int32 app_height = 4;
-  optional string name = 5;
+  optional string name = 5 [ (.android.privacy).dest = DEST_EXPLICIT ];
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index cb375d5..f4715fc 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3121,6 +3121,12 @@
     <permission android:name="android.permission.CONFIGURE_DISPLAY_COLOR_MODE"
         android:protectionLevel="signature" />
 
+    <!-- Allows an application to control the color saturation of the display.
+         @hide
+         @SystemApi -->
+    <permission android:name="android.permission.CONTROL_DISPLAY_SATURATION"
+        android:protectionLevel="signature|privileged" />
+
     <!-- Allows an application to collect usage infomation about brightness slider changes.
          <p>Not for use by third-party applications.</p>
          @hide
diff --git a/core/res/res/values-land/dimens.xml b/core/res/res/values-land/dimens.xml
index 351bd81..265eaaf 100644
--- a/core/res/res/values-land/dimens.xml
+++ b/core/res/res/values-land/dimens.xml
@@ -29,10 +29,7 @@
 
     <!-- Height of the status bar -->
     <dimen name="status_bar_height">@dimen/status_bar_height_landscape</dimen>
-    <!-- Height of area above QQS where battery/time go -->
-    <dimen name="quick_qs_offset_height">@dimen/status_bar_height_landscape</dimen>
-    <!-- Total height of QQS in landscape, this is effectively status_bar_height_landscape + 128 -->
-    <dimen name="quick_qs_total_height">152dp</dimen>
+
     <!-- Default height of an action bar. -->
     <dimen name="action_bar_default_height">40dip</dimen>
     <!-- Vertical padding around action bar icons. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 354880c..cb8d629 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1670,7 +1670,6 @@
   <java-symbol type="dimen" name="navigation_bar_height_landscape_car_mode" />
   <java-symbol type="dimen" name="navigation_bar_width_car_mode" />
   <java-symbol type="dimen" name="status_bar_height" />
-  <java-symbol type="dimen" name="quick_qs_offset_height" />
   <java-symbol type="dimen" name="quick_qs_total_height" />
   <java-symbol type="drawable" name="ic_jog_dial_sound_off" />
   <java-symbol type="drawable" name="ic_jog_dial_sound_on" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 4b9465d..dfc99f6 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -267,6 +267,7 @@
                     Settings.Global.LOW_POWER_MODE,
                     Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL_MAX,
                     Settings.Global.LOW_POWER_MODE_STICKY,
+                    Settings.Global.LOW_POWER_MODE_SUGGESTION_PARAMS,
                     Settings.Global.LTE_SERVICE_FORCED,
                     Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
                     Settings.Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY,
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
index afc4bd5..5d58f55 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
@@ -37,9 +37,10 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.Calendar;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
 import java.util.Locale;
-import java.util.TimeZone;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -163,8 +164,9 @@
 
     @Test
     public void testParcelOptions() {
-        Calendar referenceTime = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.US);
-        referenceTime.setTimeInMillis(946771200000L);  // 2000-01-02
+        ZonedDateTime referenceTime = ZonedDateTime.ofInstant(
+                Instant.ofEpochMilli(946771200000L),  // 2000-01-02
+                ZoneId.of("UTC"));
 
         TextClassification.Options reference = new TextClassification.Options();
         reference.setDefaultLocales(new LocaleList(Locale.US, Locale.GERMANY));
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 6939907..5261c04 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -21,10 +21,12 @@
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
+import android.annotation.AnyThread;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
+import android.annotation.WorkerThread;
 import android.content.ContentResolver;
 import android.content.res.AssetFileDescriptor;
 import android.content.res.AssetManager;
@@ -65,6 +67,16 @@
 
     /**
      *  Source of the encoded image data.
+     *
+     *  <p>This object references the data that will be used to decode a
+     *  Drawable or Bitmap in {@link #decodeDrawable} or {@link #decodeBitmap}.
+     *  Constructing a {@code Source} (with one of the overloads of
+     *  {@code createSource}) can be done on any thread because the construction
+     *  simply captures values. The real work is done in decodeDrawable or
+     *  decodeBitmap.</p>
+     *
+     *  <p>Further, a Source object can be reused with different settings, or
+     *  even used simultaneously in multiple threads.</p>
      */
     public static abstract class Source {
         private Source() {}
@@ -120,7 +132,8 @@
                 int length = mBuffer.limit() - mBuffer.position();
                 return nCreate(mBuffer.array(), offset, length, this);
             }
-            return nCreate(mBuffer, mBuffer.position(), mBuffer.limit(), this);
+            ByteBuffer buffer = mBuffer.slice();
+            return nCreate(buffer, buffer.position(), buffer.limit(), this);
         }
     }
 
@@ -232,6 +245,8 @@
 
     /**
      * For backwards compatibility, this does *not* close the InputStream.
+     *
+     * Further, unlike other Sources, this one is not reusable.
      */
     private static class InputStreamSource extends Source {
         InputStreamSource(Resources res, InputStream is, int inputDensity) {
@@ -322,12 +337,17 @@
         final Resources mResources;
         final int       mResId;
         int             mResDensity;
+        private Object  mLock = new Object();
 
         @Override
         public Resources getResources() { return mResources; }
 
         @Override
-        public int getDensity() { return mResDensity; }
+        public int getDensity() {
+            synchronized (mLock) {
+                return mResDensity;
+            }
+        }
 
         @Override
         public ImageDecoder createImageDecoder() throws IOException {
@@ -336,10 +356,12 @@
             // keep it alive.
             InputStream is = mResources.openRawResource(mResId, value);
 
-            if (value.density == TypedValue.DENSITY_DEFAULT) {
-                mResDensity = DisplayMetrics.DENSITY_DEFAULT;
-            } else if (value.density != TypedValue.DENSITY_NONE) {
-                mResDensity = value.density;
+            synchronized (mLock) {
+                if (value.density == TypedValue.DENSITY_DEFAULT) {
+                    mResDensity = DisplayMetrics.DENSITY_DEFAULT;
+                } else if (value.density != TypedValue.DENSITY_NONE) {
+                    mResDensity = value.density;
+                }
             }
 
             return createFromAsset((AssetInputStream) is, this);
@@ -432,6 +454,18 @@
         public boolean isAnimated() {
             return mDecoder.mAnimated;
         }
+
+        /**
+         * If known, the color space the decoded bitmap will have. Note that the
+         * output color space is not guaranteed to be the color space the bitmap
+         * is encoded with. If not known (when the config is
+         * {@link Bitmap.Config#ALPHA_8} for instance), or there is an error,
+         * it is set to null.
+         */
+        @Nullable
+        public ColorSpace getColorSpace() {
+            return mDecoder.getColorSpace();
+        }
     };
 
     /** @removed
@@ -443,6 +477,9 @@
     /**
      *  Optional listener supplied to {@link #decodeDrawable} or
      *  {@link #decodeBitmap}.
+     *
+     *  <p>This is necessary in order to change the default settings of the
+     *  decode.</p>
      */
     public static interface OnHeaderDecodedListener {
         /**
@@ -534,6 +571,9 @@
 
         /**
          *  Retrieve the {@link Source} that was interrupted.
+         *
+         *  <p>This can be used for equality checking to find the Source which
+         *  failed to completely decode.</p>
          */
         @NonNull
         public Source getSource() {
@@ -582,16 +622,17 @@
     private final int     mHeight;
     private final boolean mAnimated;
 
-    private int     mDesiredWidth;
-    private int     mDesiredHeight;
-    private int     mAllocator = ALLOCATOR_DEFAULT;
-    private boolean mRequireUnpremultiplied = false;
-    private boolean mMutable = false;
-    private boolean mConserveMemory = false;
-    private boolean mDecodeAsAlphaMask = false;
-    private Rect    mCropRect;
-    private Rect    mOutPaddingRect;
-    private Source  mSource;
+    private int        mDesiredWidth;
+    private int        mDesiredHeight;
+    private int        mAllocator = ALLOCATOR_DEFAULT;
+    private boolean    mUnpremultipliedRequired = false;
+    private boolean    mMutable = false;
+    private boolean    mConserveMemory = false;
+    private boolean    mDecodeAsAlphaMask = false;
+    private ColorSpace mDesiredColorSpace = null;
+    private Rect       mCropRect;
+    private Rect       mOutPaddingRect;
+    private Source     mSource;
 
     private PostProcessor          mPostProcessor;
     private OnPartialImageListener mOnPartialImageListener;
@@ -645,6 +686,7 @@
      * @return a new Source object, which can be passed to
      *      {@link #decodeDrawable} or {@link #decodeBitmap}.
      */
+    @AnyThread
     @NonNull
     public static Source createSource(@NonNull Resources res, int resId)
     {
@@ -659,6 +701,7 @@
      * @return a new Source object, which can be passed to
      *      {@link #decodeDrawable} or {@link #decodeBitmap}.
      */
+    @AnyThread
     @NonNull
     public static Source createSource(@NonNull ContentResolver cr,
             @NonNull Uri uri) {
@@ -670,6 +713,7 @@
      *
      * @hide
      */
+    @AnyThread
     @NonNull
     public static Source createSource(@NonNull ContentResolver cr,
             @NonNull Uri uri, @Nullable Resources res) {
@@ -679,6 +723,7 @@
     /**
      * Create a new {@link Source} from a file in the "assets" directory.
      */
+    @AnyThread
     @NonNull
     public static Source createSource(@NonNull AssetManager assets, @NonNull String fileName) {
         return new AssetSource(assets, fileName);
@@ -696,6 +741,7 @@
      *      not within data.
      * @hide
      */
+    @AnyThread
     @NonNull
     public static Source createSource(@NonNull byte[] data, int offset,
             int length) throws ArrayIndexOutOfBoundsException {
@@ -714,6 +760,7 @@
      * See {@link #createSource(byte[], int, int).
      * @hide
      */
+    @AnyThread
     @NonNull
     public static Source createSource(@NonNull byte[] data) {
         return createSource(data, 0, data.length);
@@ -731,24 +778,35 @@
      * be modified, even after the {@code AnimatedImageDrawable} is returned.
      * {@code buffer}'s contents should never be modified during decode.</p>
      */
+    @AnyThread
     @NonNull
     public static Source createSource(@NonNull ByteBuffer buffer) {
-        return new ByteBufferSource(buffer.slice());
+        return new ByteBufferSource(buffer);
     }
 
     /**
      * Internal API used to generate bitmaps for use by Drawables (i.e. BitmapDrawable)
+     *
+     * <p>Unlike other Sources, this one cannot be reused.</p>
+     *
      * @hide
      */
+    @AnyThread
+    @NonNull
     public static Source createSource(Resources res, InputStream is) {
         return new InputStreamSource(res, is, Bitmap.getDefaultDensity());
     }
 
     /**
      * Internal API used to generate bitmaps for use by Drawables (i.e. BitmapDrawable)
+     *
+     * <p>Unlike other Sources, this one cannot be reused.</p>
+     *
      * @hide
      */
+    @AnyThread
     @TestApi
+    @NonNull
     public static Source createSource(Resources res, InputStream is, int density) {
         return new InputStreamSource(res, is, density);
     }
@@ -756,6 +814,7 @@
     /**
      * Create a new {@link Source} from a {@link java.io.File}.
      */
+    @AnyThread
     @NonNull
     public static Source createSource(@NonNull File file) {
         return new FileSource(file);
@@ -769,7 +828,7 @@
      *  height that can be achieved by sampling the encoded image. Other widths
      *  and heights may be supported, but will require an additional (internal)
      *  scaling step. Such internal scaling is *not* supported with
-     *  {@link #setRequireUnpremultiplied} set to {@code true}.</p>
+     *  {@link #setUnpremultipliedRequired} set to {@code true}.</p>
      *
      *  @param sampleSize Sampling rate of the encoded image.
      *  @return {@link android.util.Size} of the width and height after
@@ -806,7 +865,11 @@
      *  image, which can be retrieved from the {@link ImageInfo} in
      *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
      *
-     *  <p>Only the last call to this or {@link #setSampleSize} is respected.</p>
+     *  <p>Only the last call to this or {@link #setTargetSampleSize} is
+     *  respected.</p>
+     *
+     *  <p>Like all setters on ImageDecoder, this must be called inside
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
      *
      *  @param width must be greater than 0.
      *  @param height must be greater than 0.
@@ -824,11 +887,11 @@
     }
 
     /** @removed
-     * @deprecated Renamed to {@link #setSampleSize}.
+     * @deprecated Renamed to {@link #setTargetSampleSize}.
      */
     @java.lang.Deprecated
     public ImageDecoder setResize(int sampleSize) {
-        return this.setSampleSize(sampleSize);
+        return this.setTargetSampleSize(sampleSize);
     }
 
     private int getTargetDimension(int original, int sampleSize, int computed) {
@@ -874,10 +937,13 @@
      *
      *  <p>Only the last call to this or {@link #setTargetSize} is respected.</p>
      *
+     *  <p>Like all setters on ImageDecoder, this must be called inside
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     *
      *  @param sampleSize Sampling rate of the encoded image.
      *  @return this object for chaining.
      */
-    public ImageDecoder setSampleSize(int sampleSize) {
+    public ImageDecoder setTargetSampleSize(int sampleSize) {
         Size size = this.getSampledSize(sampleSize);
         int targetWidth = getTargetDimension(mWidth, sampleSize, size.getWidth());
         int targetHeight = getTargetDimension(mHeight, sampleSize, size.getHeight());
@@ -895,7 +961,7 @@
      *  Will typically result in a {@link Bitmap.Config#HARDWARE}
      *  allocation, but may be software for small images. In addition, this will
      *  switch to software when HARDWARE is incompatible, e.g.
-     *  {@link #setMutable}, {@link #setDecodeAsAlphaMask}.
+     *  {@link #setMutableRequired}, {@link #setDecodeAsAlphaMaskEnabled}.
      */
     public static final int ALLOCATOR_DEFAULT = 0;
 
@@ -918,8 +984,8 @@
      *  Require a {@link Bitmap.Config#HARDWARE} {@link Bitmap}.
      *
      *  When this is combined with incompatible options, like
-     *  {@link #setMutable} or {@link #setDecodeAsAlphaMask}, {@link #decodeDrawable}
-     *  / {@link #decodeBitmap} will throw an
+     *  {@link #setMutableRequired} or {@link #setDecodeAsAlphaMaskEnabled},
+     *  {@link #decodeDrawable} / {@link #decodeBitmap} will throw an
      *  {@link java.lang.IllegalStateException}.
      */
     public static final int ALLOCATOR_HARDWARE = 3;
@@ -934,7 +1000,10 @@
     /**
      *  Choose the backing for the pixel memory.
      *
-     *  This is ignored for animated drawables.
+     *  <p>This is ignored for animated drawables.</p>
+     *
+     *  <p>Like all setters on ImageDecoder, this must be called inside
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
      *
      *  @param allocator Type of allocator to use.
      *  @return this object for chaining.
@@ -968,18 +1037,37 @@
      *  {@link Drawable} will throw an {@link java.lang.IllegalStateException}.
      *  </p>
      *
+     *  <p>Like all setters on ImageDecoder, this must be called inside
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     *
      *  @return this object for chaining.
      */
-    public ImageDecoder setRequireUnpremultiplied(boolean requireUnpremultiplied) {
-        mRequireUnpremultiplied = requireUnpremultiplied;
+    public ImageDecoder setUnpremultipliedRequired(boolean unpremultipliedRequired) {
+        mUnpremultipliedRequired = unpremultipliedRequired;
         return this;
     }
 
+    /** @removed
+     * @deprecated Renamed to {@link #setUnpremultipliedRequired}.
+     */
+    @java.lang.Deprecated
+    public ImageDecoder setRequireUnpremultiplied(boolean unpremultipliedRequired) {
+        return this.setUnpremultipliedRequired(unpremultipliedRequired);
+    }
+
     /**
      *  Return whether the {@link Bitmap} will have unpremultiplied pixels.
      */
+    public boolean isUnpremultipliedRequired() {
+        return mUnpremultipliedRequired;
+    }
+
+    /** @removed
+     * @deprecated Renamed to {@link #isUnpremultipliedRequired}.
+     */
+    @java.lang.Deprecated
     public boolean getRequireUnpremultiplied() {
-        return mRequireUnpremultiplied;
+        return this.isUnpremultipliedRequired();
     }
 
     /**
@@ -995,6 +1083,9 @@
      *  {@link Canvas} will be recorded immediately and then applied to each
      *  frame.</p>
      *
+     *  <p>Like all setters on ImageDecoder, this must be called inside
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     *
      *  @return this object for chaining.
      */
     public ImageDecoder setPostProcessor(@Nullable PostProcessor p) {
@@ -1016,6 +1107,9 @@
      *  <p>Will be called if there is an error in the input. Without one, an
      *  error will result in an Exception being thrown.</p>
      *
+     *  <p>Like all setters on ImageDecoder, this must be called inside
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     *
      *  @return this object for chaining.
      */
     public ImageDecoder setOnPartialImageListener(@Nullable OnPartialImageListener l) {
@@ -1043,6 +1137,9 @@
      *  {@link BitmapRegionDecoder#decodeRegion}. This supports all formats,
      *  but merely crops the output.</p>
      *
+     *  <p>Like all setters on ImageDecoder, this must be called inside
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     *
      *  @return this object for chaining.
      */
     public ImageDecoder setCrop(@Nullable Rect subset) {
@@ -1064,6 +1161,9 @@
      *  If the image is a nine patch, this Rect will be set to the padding
      *  rectangle during decode. Otherwise it will not be modified.
      *
+     *  <p>Like all setters on ImageDecoder, this must be called inside
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     *
      *  @return this object for chaining.
      *
      *  @hide
@@ -1089,20 +1189,39 @@
      *  order to modify. Attempting to decode a mutable {@link Drawable} will
      *  throw an {@link java.lang.IllegalStateException}.</p>
      *
+     *  <p>Like all setters on ImageDecoder, this must be called inside
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     *
      *  @return this object for chaining.
      */
-    public ImageDecoder setMutable(boolean mutable) {
+    public ImageDecoder setMutableRequired(boolean mutable) {
         mMutable = mutable;
         return this;
     }
 
+    /** @removed
+     * @deprecated Renamed to {@link #setMutableRequired}.
+     */
+    @java.lang.Deprecated
+    public ImageDecoder setMutable(boolean mutable) {
+        return this.setMutableRequired(mutable);
+    }
+
     /**
      *  Return whether the {@link Bitmap} will be mutable.
      */
-    public boolean getMutable() {
+    public boolean isMutableRequired() {
         return mMutable;
     }
 
+    /** @removed
+     * @deprecated Renamed to {@link #isMutableRequired}.
+     */
+    @java.lang.Deprecated
+    public boolean getMutable() {
+        return this.isMutableRequired();
+    }
+
     /**
      *  Specify whether to potentially save RAM at the expense of quality.
      *
@@ -1115,6 +1234,9 @@
      *  This necessarily lowers the quality of the output, but saves half
      *  the memory used.</p>
      *
+     *  <p>Like all setters on ImageDecoder, this must be called inside
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     *
      *  @return this object for chaining.
      */
     public ImageDecoder setConserveMemory(boolean conserveMemory) {
@@ -1140,20 +1262,31 @@
      *  with only one channel, treat that channel as alpha. Otherwise this call has
      *  no effect.</p>
      *
-     *  <p>setDecodeAsAlphaMask is incompatible with {@link #ALLOCATOR_HARDWARE}. Trying to
+     *  <p>This is incompatible with {@link #ALLOCATOR_HARDWARE}. Trying to
      *  combine them will result in {@link #decodeDrawable}/
      *  {@link #decodeBitmap} throwing an
      *  {@link java.lang.IllegalStateException}.</p>
      *
+     *  <p>Like all setters on ImageDecoder, this must be called inside
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     *
      *  @return this object for chaining.
      */
-    public ImageDecoder setDecodeAsAlphaMask(boolean decodeAsAlphaMask) {
-        mDecodeAsAlphaMask = decodeAsAlphaMask;
+    public ImageDecoder setDecodeAsAlphaMaskEnabled(boolean enabled) {
+        mDecodeAsAlphaMask = enabled;
         return this;
     }
 
     /** @removed
-     * @deprecated Call {@link #setDecodeAsAlphaMask} instead.
+     * @deprecated Renamed to {@link #setDecodeAsAlphaMaskEnabled}.
+     */
+    @java.lang.Deprecated
+    public ImageDecoder setDecodeAsAlphaMask(boolean enabled) {
+        return this.setDecodeAsAlphaMaskEnabled(enabled);
+    }
+
+    /** @removed
+     * @deprecated Renamed to {@link #setDecodeAsAlphaMaskEnabled}.
      */
     @java.lang.Deprecated
     public ImageDecoder setAsAlphaMask(boolean asAlphaMask) {
@@ -1163,22 +1296,65 @@
     /**
      *  Return whether to treat single channel input as alpha.
      *
-     *  <p>This returns whether {@link #setDecodeAsAlphaMask} was set to {@code true}.
-     *  It may still return {@code true} even if the image has more than one
-     *  channel and therefore will not be treated as an alpha mask.</p>
+     *  <p>This returns whether {@link #setDecodeAsAlphaMaskEnabled} was set to
+     *  {@code true}. It may still return {@code true} even if the image has
+     *  more than one channel and therefore will not be treated as an alpha
+     *  mask.</p>
      */
+    public boolean isDecodeAsAlphaMaskEnabled() {
+        return mDecodeAsAlphaMask;
+    }
+
+    /** @removed
+     * @deprecated Renamed to {@link #isDecodeAsAlphaMaskEnabled}.
+     */
+    @java.lang.Deprecated
     public boolean getDecodeAsAlphaMask() {
         return mDecodeAsAlphaMask;
     }
 
     /** @removed
-     * @deprecated Call {@link #getDecodeAsAlphaMask} instead.
+     * @deprecated Renamed to {@link #isDecodeAsAlphaMaskEnabled}.
      */
     @java.lang.Deprecated
     public boolean getAsAlphaMask() {
         return this.getDecodeAsAlphaMask();
     }
 
+    /**
+     * Specify the desired {@link ColorSpace} for the output.
+     *
+     * <p>If non-null, the decoder will try to decode into this
+     * color space. If it is null, which is the default, or the request cannot
+     * be met, the decoder will pick either the color space embedded in the
+     * image or the color space best suited for the requested image
+     * configuration (for instance {@link ColorSpace.Named#SRGB sRGB} for
+     * the {@link Bitmap.Config#ARGB_8888} configuration).</p>
+     *
+     * <p>{@link Bitmap.Config#RGBA_F16} always uses the
+     * {@link ColorSpace.Named#LINEAR_EXTENDED_SRGB scRGB} color space).
+     * Bitmaps in other configurations without an embedded color space are
+     * assumed to be in the {@link ColorSpace.Named#SRGB sRGB} color space.</p>
+     *
+     * <p class="note">Only {@link ColorSpace.Model#RGB} color spaces are
+     * currently supported. An <code>IllegalArgumentException</code> will
+     * be thrown by the decode methods when setting a non-RGB color space
+     * such as {@link ColorSpace.Named#CIE_LAB Lab}.</p>
+     *
+     * <p class="note">The specified color space's transfer function must be
+     * an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}. An
+     * <code>IllegalArgumentException</code> will be thrown by the decode methods
+     * if calling {@link ColorSpace.Rgb#getTransferParameters()} on the
+     * specified color space returns null.</p>
+     *
+     * <p>Like all setters on ImageDecoder, this must be called inside
+     * {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     */
+    public ImageDecoder setTargetColorSpace(ColorSpace colorSpace) {
+        mDesiredColorSpace = colorSpace;
+        return this;
+    }
+
     @Override
     public void close() {
         mCloseGuard.close();
@@ -1214,9 +1390,20 @@
             }
         }
 
-        if (mPostProcessor != null && mRequireUnpremultiplied) {
+        if (mPostProcessor != null && mUnpremultipliedRequired) {
             throw new IllegalStateException("Cannot draw to unpremultiplied pixels!");
         }
+
+        if (mDesiredColorSpace != null) {
+            if (!(mDesiredColorSpace instanceof ColorSpace.Rgb)) {
+                throw new IllegalArgumentException("The target color space must use the "
+                            + "RGB color model - provided: " + mDesiredColorSpace);
+            }
+            if (((ColorSpace.Rgb) mDesiredColorSpace).getTransferParameters() == null) {
+                throw new IllegalArgumentException("The target color space must use an "
+                            + "ICC parametric transfer function - provided: " + mDesiredColorSpace);
+            }
+        }
     }
 
     private static void checkSubset(int width, int height, Rect r) {
@@ -1229,13 +1416,14 @@
         }
     }
 
+    @WorkerThread
     @NonNull
     private Bitmap decodeBitmapInternal() throws IOException {
         checkState();
         return nDecodeBitmap(mNativePtr, this, mPostProcessor != null,
                 mDesiredWidth, mDesiredHeight, mCropRect,
-                mMutable, mAllocator, mRequireUnpremultiplied,
-                mConserveMemory, mDecodeAsAlphaMask);
+                mMutable, mAllocator, mUnpremultipliedRequired,
+                mConserveMemory, mDecodeAsAlphaMask, mDesiredColorSpace);
     }
 
     private void callHeaderDecoded(@Nullable OnHeaderDecodedListener listener,
@@ -1257,10 +1445,12 @@
      *  @param listener for learning the {@link ImageInfo} and changing any
      *      default settings on the {@code ImageDecoder}. This will be called on
      *      the same thread as {@code decodeDrawable} before that method returns.
+     *      This is required in order to change any of the default settings.
      *  @return Drawable for displaying the image.
      *  @throws IOException if {@code src} is not found, is an unsupported
      *      format, or cannot be decoded for any reason.
      */
+    @WorkerThread
     @NonNull
     public static Drawable decodeDrawable(@NonNull Source src,
             @NonNull OnHeaderDecodedListener listener) throws IOException {
@@ -1271,6 +1461,7 @@
         return decodeDrawableImpl(src, listener);
     }
 
+    @WorkerThread
     @NonNull
     private static Drawable decodeDrawableImpl(@NonNull Source src,
             @Nullable OnHeaderDecodedListener listener) throws IOException {
@@ -1278,7 +1469,7 @@
             decoder.mSource = src;
             decoder.callHeaderDecoded(listener, src);
 
-            if (decoder.mRequireUnpremultiplied) {
+            if (decoder.mUnpremultipliedRequired) {
                 // Though this could be supported (ignored) for opaque images,
                 // it seems better to always report this error.
                 throw new IllegalStateException("Cannot decode a Drawable " +
@@ -1331,8 +1522,18 @@
     }
 
     /**
-     * See {@link #decodeDrawable(Source, OnHeaderDecodedListener)}.
+     *  Create a {@link Drawable} from a {@code Source}.
+     *
+     *  <p>Since there is no {@link OnHeaderDecodedListener}, the default
+     *  settings will be used. In order to change any settings, call
+     *  {@link #decodeDrawable(Source, OnHeaderDecodedListener)} instead.</p>
+     *
+     *  @param src representing the encoded image.
+     *  @return Drawable for displaying the image.
+     *  @throws IOException if {@code src} is not found, is an unsupported
+     *      format, or cannot be decoded for any reason.
      */
+    @WorkerThread
     @NonNull
     public static Drawable decodeDrawable(@NonNull Source src)
             throws IOException {
@@ -1346,10 +1547,12 @@
      *  @param listener for learning the {@link ImageInfo} and changing any
      *      default settings on the {@code ImageDecoder}. This will be called on
      *      the same thread as {@code decodeBitmap} before that method returns.
+     *      This is required in order to change any of the default settings.
      *  @return Bitmap containing the image.
      *  @throws IOException if {@code src} is not found, is an unsupported
      *      format, or cannot be decoded for any reason.
      */
+    @WorkerThread
     @NonNull
     public static Bitmap decodeBitmap(@NonNull Source src,
             @NonNull OnHeaderDecodedListener listener) throws IOException {
@@ -1360,6 +1563,7 @@
         return decodeBitmapImpl(src, listener);
     }
 
+    @WorkerThread
     @NonNull
     private static Bitmap decodeBitmapImpl(@NonNull Source src,
             @Nullable OnHeaderDecodedListener listener) throws IOException {
@@ -1425,9 +1629,24 @@
         return nGetMimeType(mNativePtr);
     }
 
+    @Nullable
+    private ColorSpace getColorSpace() {
+        return nGetColorSpace(mNativePtr);
+    }
+
     /**
-     *  See {@link #decodeBitmap(Source, OnHeaderDecodedListener)}.
+     *  Create a {@link Bitmap} from a {@code Source}.
+     *
+     *  <p>Since there is no {@link OnHeaderDecodedListener}, the default
+     *  settings will be used. In order to change any settings, call
+     *  {@link #decodeBitmap(Source, OnHeaderDecodedListener)} instead.</p>
+     *
+     *  @param src representing the encoded image.
+     *  @return Bitmap containing the image.
+     *  @throws IOException if {@code src} is not found, is an unsupported
+     *      format, or cannot be decoded for any reason.
      */
+    @WorkerThread
     @NonNull
     public static Bitmap decodeBitmap(@NonNull Source src) throws IOException {
         return decodeBitmapImpl(src, null);
@@ -1473,12 +1692,14 @@
             boolean doPostProcess,
             int width, int height,
             @Nullable Rect cropRect, boolean mutable,
-            int allocator, boolean requireUnpremul,
-            boolean conserveMemory, boolean decodeAsAlphaMask)
+            int allocator, boolean unpremulRequired,
+            boolean conserveMemory, boolean decodeAsAlphaMask,
+            @Nullable ColorSpace desiredColorSpace)
         throws IOException;
     private static native Size nGetSampledSize(long nativePtr,
                                                int sampleSize);
     private static native void nGetPadding(long nativePtr, @NonNull Rect outRect);
     private static native void nClose(long nativePtr);
     private static native String nGetMimeType(long nativePtr);
+    private static native ColorSpace nGetColorSpace(long nativePtr);
 }
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 1e2ebf8..81644eb 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -16,6 +16,7 @@
 
 package android.security;
 
+import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.app.Application;
 import android.app.KeyguardManager;
@@ -279,7 +280,7 @@
     /**
      * Attempt to lock the keystore for {@code user}.
      *
-     * @param user Android user to lock.
+     * @param userId Android user to lock.
      * @return whether {@code user}'s keystore was locked.
      */
     public boolean lock(int userId) {
@@ -300,7 +301,7 @@
      * This is required before keystore entries created with FLAG_ENCRYPTED can be accessed or
      * created.
      *
-     * @param user Android user ID to operate on
+     * @param userId Android user ID to operate on
      * @param password user's keystore password. Should be the most recent value passed to
      * {@link #onUserPasswordChanged} for the user.
      *
@@ -546,6 +547,9 @@
         try {
             args = args != null ? args : new KeymasterArguments();
             entropy = entropy != null ? entropy : new byte[0];
+            if (!args.containsTag(KeymasterDefs.KM_TAG_USER_ID)) {
+                args.addUnsignedInt(KeymasterDefs.KM_TAG_USER_ID, ActivityManager.getCurrentUser());
+            }
             return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid);
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 4b9f3c80..5d596cb 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -266,6 +266,7 @@
     private final boolean mInvalidatedByBiometricEnrollment;
     private final boolean mIsStrongBoxBacked;
     private final boolean mUserConfirmationRequired;
+    private final boolean mUnlockedDeviceRequired;
 
     /**
      * @hide should be built with Builder
@@ -296,7 +297,8 @@
             boolean userAuthenticationValidWhileOnBody,
             boolean invalidatedByBiometricEnrollment,
             boolean isStrongBoxBacked,
-            boolean userConfirmationRequired) {
+            boolean userConfirmationRequired,
+            boolean unlockedDeviceRequired) {
         if (TextUtils.isEmpty(keyStoreAlias)) {
             throw new IllegalArgumentException("keyStoreAlias must not be empty");
         }
@@ -345,6 +347,7 @@
         mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
         mIsStrongBoxBacked = isStrongBoxBacked;
         mUserConfirmationRequired = userConfirmationRequired;
+        mUnlockedDeviceRequired = unlockedDeviceRequired;
     }
 
     /**
@@ -670,6 +673,15 @@
     }
 
     /**
+     * @hide Returns {@code true} if the key cannot be used unless the device screen is unlocked.
+     *
+     * @see Builder#setUnlockedDeviceRequired(boolean)
+     */
+    public boolean isUnlockedDeviceRequired() {
+        return mUnlockedDeviceRequired;
+    }
+
+    /**
      * @hide
      */
     public long getBoundToSpecificSecureUserId() {
@@ -707,6 +719,7 @@
         private boolean mInvalidatedByBiometricEnrollment = true;
         private boolean mIsStrongBoxBacked = false;
         private boolean mUserConfirmationRequired;
+        private boolean mUnlockedDeviceRequired = false;
 
         /**
          * Creates a new instance of the {@code Builder}.
@@ -1275,6 +1288,18 @@
         }
 
         /**
+         * @hide Sets whether the keystore requires the screen to be unlocked before allowing decryption
+         * using this key. If this is set to {@code true}, any attempt to decrypt using this key
+         * while the screen is locked will fail. A locked device requires a PIN, password,
+         * fingerprint, or other trusted factor to access.
+         */
+        @NonNull
+        public Builder setUnlockedDeviceRequired(boolean unlockedDeviceRequired) {
+            mUnlockedDeviceRequired = unlockedDeviceRequired;
+            return this;
+        }
+
+        /**
          * Builds an instance of {@code KeyGenParameterSpec}.
          */
         @NonNull
@@ -1305,7 +1330,8 @@
                     mUserAuthenticationValidWhileOnBody,
                     mInvalidatedByBiometricEnrollment,
                     mIsStrongBoxBacked,
-                    mUserConfirmationRequired);
+                    mUserConfirmationRequired,
+                    mUnlockedDeviceRequired);
         }
     }
 }
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 95eeec7..cc7870c 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -224,12 +224,13 @@
     private final boolean mRandomizedEncryptionRequired;
     private final boolean mUserAuthenticationRequired;
     private final int mUserAuthenticationValidityDurationSeconds;
-    private final boolean mTrustedUserPresenceRequred;
+    private final boolean mTrustedUserPresenceRequired;
     private final boolean mUserAuthenticationValidWhileOnBody;
     private final boolean mInvalidatedByBiometricEnrollment;
     private final long mBoundToSecureUserId;
     private final boolean mCriticalToDeviceEncryption;
     private final boolean mUserConfirmationRequired;
+    private final boolean mUnlockedDeviceRequired;
 
     private KeyProtection(
             Date keyValidityStart,
@@ -243,12 +244,13 @@
             boolean randomizedEncryptionRequired,
             boolean userAuthenticationRequired,
             int userAuthenticationValidityDurationSeconds,
-            boolean trustedUserPresenceRequred,
+            boolean trustedUserPresenceRequired,
             boolean userAuthenticationValidWhileOnBody,
             boolean invalidatedByBiometricEnrollment,
             long boundToSecureUserId,
             boolean criticalToDeviceEncryption,
-            boolean userConfirmationRequired) {
+            boolean userConfirmationRequired,
+            boolean unlockedDeviceRequired) {
         mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
         mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
         mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
@@ -262,12 +264,13 @@
         mRandomizedEncryptionRequired = randomizedEncryptionRequired;
         mUserAuthenticationRequired = userAuthenticationRequired;
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
-        mTrustedUserPresenceRequred = trustedUserPresenceRequred;
+        mTrustedUserPresenceRequired = trustedUserPresenceRequired;
         mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
         mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
         mBoundToSecureUserId = boundToSecureUserId;
         mCriticalToDeviceEncryption = criticalToDeviceEncryption;
         mUserConfirmationRequired = userConfirmationRequired;
+        mUnlockedDeviceRequired = unlockedDeviceRequired;
     }
 
     /**
@@ -444,7 +447,7 @@
      * been performed between the {@code Signature.initSign()} and {@code Signature.sign()} calls.
      */
     public boolean isTrustedUserPresenceRequired() {
-        return mTrustedUserPresenceRequred;
+        return mTrustedUserPresenceRequired;
     }
 
     /**
@@ -505,6 +508,15 @@
     }
 
     /**
+     * @hide Returns {@code true} if the key cannot be used unless the device screen is unlocked.
+     *
+     * @see Builder#setUnlockedDeviceRequired(boolean)
+     */
+    public boolean isUnlockedDeviceRequired() {
+        return mUnlockedDeviceRequired;
+    }
+
+    /**
      * Builder of {@link KeyProtection} instances.
      */
     public final static class Builder {
@@ -524,6 +536,8 @@
         private boolean mUserAuthenticationValidWhileOnBody;
         private boolean mInvalidatedByBiometricEnrollment = true;
         private boolean mUserConfirmationRequired;
+        private boolean mUnlockedDeviceRequired = false;
+
         private long mBoundToSecureUserId = GateKeeper.INVALID_SECURE_USER_ID;
         private boolean mCriticalToDeviceEncryption = false;
 
@@ -914,6 +928,18 @@
         }
 
         /**
+         * @hide Sets whether the keystore requires the screen to be unlocked before allowing decryption
+         * using this key. If this is set to {@code true}, any attempt to decrypt using this key
+         * while the screen is locked will fail. A locked device requires a PIN, password,
+         * fingerprint, or other trusted factor to access.
+         */
+        @NonNull
+        public Builder setUnlockedDeviceRequired(boolean unlockedDeviceRequired) {
+            mUnlockedDeviceRequired = unlockedDeviceRequired;
+            return this;
+        }
+
+        /**
          * Builds an instance of {@link KeyProtection}.
          *
          * @throws IllegalArgumentException if a required field is missing
@@ -937,7 +963,8 @@
                     mInvalidatedByBiometricEnrollment,
                     mBoundToSecureUserId,
                     mCriticalToDeviceEncryption,
-                    mUserConfirmationRequired);
+                    mUserConfirmationRequired,
+                    mUnlockedDeviceRequired);
         }
     }
 }
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
index 0ef08f2..6e50121 100644
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore/KeymasterUtils.java
@@ -16,9 +16,8 @@
 
 package android.security.keystore;
 
-import android.util.Log;
+import android.app.ActivityManager;
 import android.hardware.fingerprint.FingerprintManager;
-import android.os.UserHandle;
 import android.security.GateKeeper;
 import android.security.KeyStore;
 import android.security.keymaster.KeymasterArguments;
@@ -101,8 +100,9 @@
      *         state (e.g., secure lock screen not set up) for generating or importing keys that
      *         require user authentication.
      */
-    public static void addUserAuthArgs(KeymasterArguments args,
-            UserAuthArgs spec) {
+    public static void addUserAuthArgs(KeymasterArguments args, UserAuthArgs spec) {
+        args.addUnsignedInt(KeymasterDefs.KM_TAG_USER_ID, ActivityManager.getCurrentUser());
+
         if (spec.isUserConfirmationRequired()) {
             args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED);
         }
@@ -111,6 +111,10 @@
             args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
         }
 
+        if (spec.isUnlockedDeviceRequired()) {
+            args.addBoolean(KeymasterDefs.KM_TAG_UNLOCKED_DEVICE_REQUIRED);
+        }
+
         if (!spec.isUserAuthenticationRequired()) {
             args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
             return;
diff --git a/keystore/java/android/security/keystore/UserAuthArgs.java b/keystore/java/android/security/keystore/UserAuthArgs.java
index 1949592..ad18ff8 100644
--- a/keystore/java/android/security/keystore/UserAuthArgs.java
+++ b/keystore/java/android/security/keystore/UserAuthArgs.java
@@ -33,5 +33,6 @@
     boolean isUserConfirmationRequired();
     long getBoundToSpecificSecureUserId();
     boolean isTrustedUserPresenceRequired();
+    boolean isUnlockedDeviceRequired();
 
 }
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index d9584db..293e45f 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -34,7 +34,8 @@
     }
 }
 
-bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer) {
+bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer,
+                              const SkRect* dstRect) {
     if (context == nullptr) {
         SkDEBUGF(("Attempting to draw LayerDrawable into an unsupported surface"));
         return false;
@@ -43,8 +44,8 @@
     SkMatrix layerTransform;
     layer->getTransform().copyTo(layerTransform);
     sk_sp<SkImage> layerImage;
-    int layerWidth = layer->getWidth();
-    int layerHeight = layer->getHeight();
+    const int layerWidth = layer->getWidth();
+    const int layerHeight = layer->getHeight();
     if (layer->getApi() == Layer::Api::OpenGL) {
         GlLayer* glLayer = static_cast<GlLayer*>(layer);
         GrGLTextureInfo externalTexture;
@@ -62,21 +63,21 @@
     }
 
     if (layerImage) {
-        SkMatrix textureMatrix;
-        layer->getTexTransform().copyTo(textureMatrix);
+        SkMatrix textureMatrixInv;
+        layer->getTexTransform().copyTo(textureMatrixInv);
         // TODO: after skia bug https://bugs.chromium.org/p/skia/issues/detail?id=7075 is fixed
         // use bottom left origin and remove flipV and invert transformations.
         SkMatrix flipV;
         flipV.setAll(1, 0, 0, 0, -1, 1, 0, 0, 1);
-        textureMatrix.preConcat(flipV);
-        textureMatrix.preScale(1.0f / layerWidth, 1.0f / layerHeight);
-        textureMatrix.postScale(layerWidth, layerHeight);
-        SkMatrix textureMatrixInv;
-        if (!textureMatrix.invert(&textureMatrixInv)) {
-            textureMatrixInv = textureMatrix;
+        textureMatrixInv.preConcat(flipV);
+        textureMatrixInv.preScale(1.0f / layerWidth, 1.0f / layerHeight);
+        textureMatrixInv.postScale(layerWidth, layerHeight);
+        SkMatrix textureMatrix;
+        if (!textureMatrixInv.invert(&textureMatrix)) {
+            textureMatrix = textureMatrixInv;
         }
 
-        SkMatrix matrix = SkMatrix::Concat(layerTransform, textureMatrixInv);
+        SkMatrix matrix = SkMatrix::Concat(layerTransform, textureMatrix);
 
         SkPaint paint;
         paint.setAlpha(layer->getAlpha());
@@ -88,7 +89,20 @@
             canvas->save();
             canvas->concat(matrix);
         }
-        canvas->drawImage(layerImage.get(), 0, 0, &paint);
+        if (dstRect) {
+            SkMatrix matrixInv;
+            if (!matrix.invert(&matrixInv)) {
+                matrixInv = matrix;
+            }
+            SkRect srcRect = SkRect::MakeIWH(layerWidth, layerHeight);
+            matrixInv.mapRect(&srcRect);
+            SkRect skiaDestRect = *dstRect;
+            matrixInv.mapRect(&skiaDestRect);
+            canvas->drawImageRect(layerImage.get(), srcRect, skiaDestRect, &paint,
+                                  SkCanvas::kFast_SrcRectConstraint);
+        } else {
+            canvas->drawImage(layerImage.get(), 0, 0, &paint);
+        }
         // restore the original matrix
         if (nonIdentityMatrix) {
             canvas->restore();
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.h b/libs/hwui/pipeline/skia/LayerDrawable.h
index 3450387..18d1184 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.h
+++ b/libs/hwui/pipeline/skia/LayerDrawable.h
@@ -32,7 +32,8 @@
 public:
     explicit LayerDrawable(DeferredLayerUpdater* layerUpdater) : mLayerUpdater(layerUpdater) {}
 
-    static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer);
+    static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer,
+                          const SkRect* dstRect = nullptr);
 
 protected:
     virtual SkRect onGetBounds() override {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 365d740..74cfb28 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -138,7 +138,9 @@
                                                               SkBudgeted::kYes, bitmap->info());
 
     Layer* layer = deferredLayer->backingLayer();
-    if (LayerDrawable::DrawLayer(mRenderThread.getGrContext(), tmpSurface->getCanvas(), layer)) {
+    const SkRect dstRect = SkRect::MakeIWH(bitmap->width(), bitmap->height());
+    if (LayerDrawable::DrawLayer(mRenderThread.getGrContext(), tmpSurface->getCanvas(), layer,
+                                 &dstRect)) {
         sk_sp<SkImage> tmpImage = tmpSurface->makeImageSnapshot();
         if (tmpImage->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) {
             bitmap->notifyPixelsChanged();
diff --git a/libs/incident/proto/android/privacy.proto b/libs/incident/proto/android/privacy.proto
index f29f57f..1ef36df 100644
--- a/libs/incident/proto/android/privacy.proto
+++ b/libs/incident/proto/android/privacy.proto
@@ -16,13 +16,13 @@
 
 syntax = "proto2";
 
-option java_package = "android";
+package android;
+
+option java_package = "com.android.incident";
 option java_multiple_files = true;
 
 import "google/protobuf/descriptor.proto";
 
-package android;
-
 enum Destination {
     // Fields or messages annotated with DEST_LOCAL must never be
     // extracted from the device automatically. They can be accessed
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index befbade..aef31b1 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -4099,8 +4099,8 @@
 
     /** The player was started because it was used as the next player for another
      * player, which just completed playback.
+     * @see android.media.MediaPlayer#setNextMediaPlayer(MediaPlayer)
      * @see android.media.MediaPlayer.OnInfoListener
-     * @hide
      */
     public static final int MEDIA_INFO_STARTED_AS_NEXT = 2;
 
diff --git a/packages/MtpDocumentsProvider/perf_tests/Android.mk b/packages/MtpDocumentsProvider/perf_tests/Android.mk
index 6504af1..e873157 100644
--- a/packages/MtpDocumentsProvider/perf_tests/Android.mk
+++ b/packages/MtpDocumentsProvider/perf_tests/Android.mk
@@ -8,5 +8,6 @@
 LOCAL_PRIVATE_PLATFORM_APIS := true
 LOCAL_INSTRUMENTATION_FOR := MtpDocumentsProvider
 LOCAL_CERTIFICATE := media
+LOCAL_COMPATIBILITY_SUITE += device-tests
 
 include $(BUILD_PACKAGE)
diff --git a/packages/MtpDocumentsProvider/perf_tests/AndroidTest.xml b/packages/MtpDocumentsProvider/perf_tests/AndroidTest.xml
new file mode 100644
index 0000000..8b7292b
--- /dev/null
+++ b/packages/MtpDocumentsProvider/perf_tests/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs MtpDocumentsProviderPerfTests metric instrumentation.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-metric-instrumentation" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="MtpDocumentsProviderPerfTests.apk" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.mtp.perftests" />
+    </test>
+</configuration>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index ee12191..f9f80eb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -163,6 +163,11 @@
         return mService.getActiveDevice();
     }
 
+    public boolean isAudioOn() {
+        if (mService == null) return false;
+        return mService.isAudioOn();
+    }
+
     public boolean isPreferred(BluetoothDevice device) {
         if (mService == null) return false;
         return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
index 28833a3..835ff07 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
@@ -22,8 +22,9 @@
 import android.os.PowerManager;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
-import android.support.annotation.VisibleForTesting;
+import android.util.KeyValueListParser;
 import android.util.Log;
+import android.util.Slog;
 
 /**
  * Utilities related to battery saver.
@@ -48,13 +49,35 @@
     public static final String ACTION_SHOW_AUTO_SAVER_SUGGESTION
             = "PNW.autoSaverSuggestion";
 
-    /**
-     * We show the auto battery saver suggestion notification when the user manually enables
-     * battery saver for the START_NTH time through the END_NTH time.
-     * (We won't show it for END_NTH + 1 time and after.)
-     */
-    private static final int AUTO_SAVER_SUGGESTION_START_NTH = 4;
-    private static final int AUTO_SAVER_SUGGESTION_END_NTH = 8;
+    private static class Parameters {
+        private final Context mContext;
+
+        /**
+         * We show the auto battery saver suggestion notification when the user manually enables
+         * battery saver for the START_NTH time through the END_NTH time.
+         * (We won't show it for END_NTH + 1 time and after.)
+         */
+        private static final int AUTO_SAVER_SUGGESTION_START_NTH = 4;
+        private static final int AUTO_SAVER_SUGGESTION_END_NTH = 8;
+
+        public final int startNth;
+        public final int endNth;
+
+        public Parameters(Context context) {
+            mContext = context;
+
+            final String newValue = Global.getString(mContext.getContentResolver(),
+                    Global.LOW_POWER_MODE_SUGGESTION_PARAMS);
+            final KeyValueListParser parser = new KeyValueListParser(',');
+            try {
+                parser.setString(newValue);
+            } catch (IllegalArgumentException e) {
+                Slog.wtf(TAG, "Bad constants: " + newValue);
+            }
+            startNth = parser.getInt("start_nth", AUTO_SAVER_SUGGESTION_START_NTH);
+            endNth = parser.getInt("end_nth", AUTO_SAVER_SUGGESTION_END_NTH);
+        }
+    }
 
     /**
      * Enable / disable battery saver by user request.
@@ -85,8 +108,10 @@
                         Secure.getInt(cr, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, 0) + 1;
                 Secure.putInt(cr, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, count);
 
-                if ((count >= AUTO_SAVER_SUGGESTION_START_NTH)
-                        && (count <= AUTO_SAVER_SUGGESTION_END_NTH)
+                final Parameters parameters = new Parameters(context);
+
+                if ((count >= parameters.startNth)
+                        && (count <= parameters.endNth)
                         && Global.getInt(cr, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0) == 0
                         && Secure.getInt(cr,
                         Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION, 0) == 0) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index 4cd23f9..9347674 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -50,7 +50,9 @@
                 }
             };
     private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder()
-            .clearCapabilities().addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build();
+            .clearCapabilities()
+            .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
+            .addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build();
     private final ConnectivityManager.NetworkCallback mNetworkCallback = new ConnectivityManager
             .NetworkCallback() {
         @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 8f80527..a128b54 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -213,6 +213,7 @@
 
         mNetworkRequest = new NetworkRequest.Builder()
                 .clearCapabilities()
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
                 .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                 .build();
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HeadsetProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HeadsetProfileTest.java
new file mode 100644
index 0000000..117f447
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HeadsetProfileTest.java
@@ -0,0 +1,60 @@
+package com.android.settingslib.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class HeadsetProfileTest {
+
+    @Mock
+    private LocalBluetoothAdapter mAdapter;
+    @Mock
+    private CachedBluetoothDeviceManager mDeviceManager;
+    @Mock
+    private LocalBluetoothProfileManager mProfileManager;
+    @Mock
+    private BluetoothHeadset mService;
+    
+    private BluetoothProfile.ServiceListener mServiceListener;
+    private HeadsetProfile mProfile;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        Context context = spy(RuntimeEnvironment.application);
+
+        doAnswer((invocation) -> {
+            mServiceListener = (BluetoothProfile.ServiceListener) invocation.getArguments()[1];
+            return null;
+        }).when(mAdapter).getProfileProxy(any(Context.class), any(), eq(BluetoothProfile.HEADSET));
+
+        mProfile = new HeadsetProfile(context, mAdapter, mDeviceManager, mProfileManager);
+        mServiceListener.onServiceConnected(BluetoothProfile.HEADSET, mService);
+    }
+
+    @Test
+    public void bluetoothProfile_shouldReturnTheAudioStatusFromBlueToothHeadsetService() {
+        when(mService.isAudioOn()).thenReturn(true);
+        assertThat(mProfile.isAudioOn()).isTrue();
+
+        when(mService.isAudioOn()).thenReturn(false);
+        assertThat(mProfile.isAudioOn()).isFalse();
+    }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
index c8bcdaa..5f4cf03 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
@@ -19,6 +19,7 @@
 import android.media.AudioManager;
 import android.media.AudioSystem;
 import android.os.Handler;
+import android.os.VibrationEffect;
 import android.util.SparseArray;
 
 import com.android.systemui.plugins.VolumeDialogController.Callbacks;
@@ -44,7 +45,8 @@
     void setRingerMode(int ringerModeNormal, boolean external);
 
     boolean hasVibrator();
-    void vibrate();
+    void vibrate(VibrationEffect effect);
+    void scheduleTouchFeedback();
 
     AudioManager getAudioManager();
 
diff --git a/packages/SystemUI/res/drawable/ic_1x_mobiledata.xml b/packages/SystemUI/res/drawable/ic_1x_mobiledata.xml
index 726d814..c0e0e59 100644
--- a/packages/SystemUI/res/drawable/ic_1x_mobiledata.xml
+++ b/packages/SystemUI/res/drawable/ic_1x_mobiledata.xml
@@ -14,17 +14,17 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="14dp"
-        android:height="24dp"
-        android:viewportWidth="14"
-        android:viewportHeight="24">
+    android:width="14dp"
+    android:height="17dp"
+    android:viewportWidth="14"
+    android:viewportHeight="17">
 
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M5.62,16.29H4.58V9.06l-1.79,0.8V8.88l2.67-1.17h0.16V16.29z" />
+        android:pathData="M3.77,13.48H2.55V5.05L0.46,5.98V4.84l3.12-1.36h0.19V13.48z" />
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M11.08,11.02l1.61-3.27h1.26l-2.22,4.23l2.27,4.3h-1.27l-1.64-3.33l-1.65,3.33H8.16l2.28-4.3L8.21,7.75h1.25L11.08,11.02z" />
+        android:pathData="M10.14,7.34l1.87-3.81h1.47L10.9,8.46l2.65,5.02h-1.48l-1.91-3.88l-1.92,3.88H6.74L9.4,8.46l-2.6-4.94h1.46L10.14,7.34z" />
     <path
-        android:pathData="M 0 0 H 13.99 V 24 H 0 V 0 Z" />
-</vector>
\ No newline at end of file
+        android:pathData="M 0 0 H 14 V 17 H 0 V 0 Z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_3g_mobiledata.xml b/packages/SystemUI/res/drawable/ic_3g_mobiledata.xml
index 7a539ff..e4a5bf8 100644
--- a/packages/SystemUI/res/drawable/ic_3g_mobiledata.xml
+++ b/packages/SystemUI/res/drawable/ic_3g_mobiledata.xml
@@ -14,17 +14,17 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="14dp"
-        android:height="24dp"
-        android:viewportWidth="14"
-        android:viewportHeight="24">
+    android:width="14dp"
+    android:height="17dp"
+    android:viewportWidth="14"
+    android:viewportHeight="17">
 
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M3.83,11.38h0.66c0.43,0,0.75-0.13,0.98-0.39s0.35-0.62,0.35-1.07c0-1-0.39-1.5-1.16-1.5c-0.37,0-0.66,0.13-0.87,0.4 S3.47,9.44,3.47,9.88H2.44c0-0.68,0.21-1.25,0.62-1.69s0.95-0.67,1.6-0.67c0.67,0,1.21,0.21,1.6,0.63s0.59,1.01,0.59,1.78 c0,0.39-0.1,0.76-0.31,1.1s-0.47,0.59-0.8,0.75c0.8,0.3,1.21,0.96,1.21,2c0,0.76-0.21,1.37-0.64,1.82s-0.98,0.68-1.66,0.68 c-0.68,0-1.22-0.21-1.64-0.64s-0.62-1-0.62-1.73h1.04c0,0.45,0.11,0.81,0.33,1.08s0.52,0.4,0.9,0.4c0.39,0,0.69-0.13,0.92-0.39 s0.34-0.66,0.34-1.2c0-1.04-0.49-1.55-1.47-1.55H3.83V11.38z" />
+        android:pathData="M1.9,7.88h0.77c0.5,0,0.88-0.15,1.15-0.46s0.4-0.72,0.4-1.25c0-1.17-0.45-1.75-1.35-1.75c-0.43,0-0.77,0.16-1.02,0.47 S1.49,5.62,1.49,6.13h-1.2c0-0.8,0.24-1.46,0.73-1.97s1.11-0.78,1.86-0.78c0.78,0,1.41,0.25,1.87,0.73S5.43,5.31,5.43,6.2 c0,0.46-0.12,0.89-0.36,1.29S4.52,8.18,4.14,8.37c0.94,0.35,1.41,1.12,1.41,2.33c0,0.89-0.25,1.6-0.74,2.12 c-0.49,0.53-1.14,0.79-1.94,0.79c-0.79,0-1.43-0.25-1.91-0.75c-0.49-0.5-0.73-1.17-0.73-2.01h1.21c0,0.53,0.13,0.95,0.38,1.26 c0.26,0.31,0.6,0.47,1.05,0.47c0.45,0,0.81-0.15,1.08-0.46s0.4-0.77,0.4-1.39c0-1.21-0.57-1.81-1.72-1.81H1.9V7.88z" />
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M14,15.11l-0.19,0.23c-0.54,0.63-1.33,0.94-2.37,0.94c-0.92,0-1.65-0.31-2.17-0.92s-0.79-1.48-0.81-2.59V11.1 c0-1.2,0.24-2.09,0.72-2.69s1.19-0.89,2.15-0.89c0.81,0,1.45,0.23,1.91,0.68s0.71,1.1,0.76,1.94h-1.07 c-0.04-0.53-0.19-0.95-0.44-1.25s-0.63-0.45-1.15-0.45c-0.61,0-1.06,0.2-1.35,0.6s-0.43,1.04-0.45,1.92v1.74 c0,0.86,0.16,1.52,0.49,1.98s0.8,0.69,1.41,0.69c0.58,0,1.02-0.14,1.32-0.42l0.16-0.15v-1.96h-1.56v-0.92H14V15.11z" />
+        android:pathData="M13.77,12.24l-0.22,0.27c-0.63,0.73-1.55,1.1-2.76,1.1c-1.08,0-1.92-0.36-2.53-1.07c-0.61-0.71-0.93-1.72-0.94-3.02V7.56 c0-1.39,0.28-2.44,0.84-3.13s1.39-1.04,2.51-1.04c0.95,0,1.69,0.26,2.23,0.79s0.83,1.28,0.89,2.26h-1.25 C12.47,5.82,12.3,5.33,12,4.98s-0.74-0.52-1.34-0.52c-0.72,0-1.24,0.23-1.57,0.7S8.59,6.37,8.58,7.4v2.03c0,1,0.19,1.77,0.57,2.31 c0.38,0.54,0.93,0.8,1.65,0.8c0.67,0,1.19-0.16,1.54-0.49l0.18-0.17V9.59H10.7V8.52h3.07V12.24z" />
     <path
-        android:pathData="M 0 0 H 14 V 24 H 0 V 0 Z" />
-</vector>
\ No newline at end of file
+        android:pathData="M 0 0 H 14 V 17 H 0 V 0 Z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_4g_mobiledata.xml b/packages/SystemUI/res/drawable/ic_4g_mobiledata.xml
index b2fab0c8..e98560b 100644
--- a/packages/SystemUI/res/drawable/ic_4g_mobiledata.xml
+++ b/packages/SystemUI/res/drawable/ic_4g_mobiledata.xml
@@ -14,17 +14,17 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="14dp"
-        android:height="24dp"
-        android:viewportWidth="14"
-        android:viewportHeight="24">
+    android:width="14dp"
+    android:height="17dp"
+    android:viewportWidth="14"
+    android:viewportHeight="17">
 
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M6.42,13.3h0.95v0.88H6.42v1.98H5.38v-1.98H2.16v-0.64l3.17-5.91h1.09C6.42,7.63,6.42,13.3,6.42,13.3z M3.31,13.3h2.07 V9.25L3.31,13.3z" />
+        android:pathData="M5.07,10.13h1.11v1.03H5.07v2.31H3.86v-2.31H0.1v-0.75l3.7-6.9h1.27V10.13z M1.44,10.13h2.42V5.4L1.44,10.13z" />
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M13.99,15.11l-0.19,0.23c-0.54,0.63-1.33,0.94-2.37,0.94c-0.92,0-1.65-0.31-2.17-0.92s-0.79-1.48-0.8-2.59V11.1 c0-1.2,0.24-2.09,0.72-2.69s1.2-0.89,2.15-0.89c0.81,0,1.45,0.23,1.91,0.68s0.71,1.1,0.76,1.94h-1.07 c-0.04-0.53-0.19-0.95-0.44-1.25s-0.63-0.45-1.14-0.45c-0.61,0-1.06,0.2-1.35,0.6s-0.43,1.04-0.45,1.92v1.74 c0,0.86,0.16,1.52,0.49,1.98s0.8,0.69,1.41,0.69c0.58,0,1.02-0.14,1.32-0.42l0.16-0.15v-1.96h-1.56v-0.92h2.62V15.11z" />
+        android:pathData="M13.9,12.24l-0.22,0.27c-0.63,0.73-1.55,1.1-2.76,1.1c-1.08,0-1.92-0.36-2.53-1.07c-0.61-0.71-0.93-1.72-0.94-3.02V7.56 c0-1.39,0.28-2.44,0.84-3.13s1.39-1.04,2.51-1.04c0.95,0,1.69,0.26,2.23,0.79s0.83,1.28,0.89,2.26h-1.25 c-0.05-0.62-0.22-1.1-0.52-1.45s-0.74-0.52-1.34-0.52c-0.72,0-1.24,0.23-1.57,0.7S8.72,6.37,8.71,7.4v2.03 c0,1,0.19,1.77,0.57,2.31c0.38,0.54,0.93,0.8,1.65,0.8c0.67,0,1.19-0.16,1.54-0.49l0.18-0.17V9.59h-1.82V8.52h3.07V12.24z" />
     <path
-        android:pathData="M 0 0 H 14 V 24 H 0 V 0 Z" />
+        android:pathData="M 0 0 H 14 V 17 H 0 V 0 Z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_4g_plus_mobiledata.xml b/packages/SystemUI/res/drawable/ic_4g_plus_mobiledata.xml
index bdbb2df..bf39ea2 100644
--- a/packages/SystemUI/res/drawable/ic_4g_plus_mobiledata.xml
+++ b/packages/SystemUI/res/drawable/ic_4g_plus_mobiledata.xml
@@ -14,20 +14,20 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="20dp"
-        android:height="24dp"
-        android:viewportWidth="20"
-        android:viewportHeight="24">
+    android:width="22dp"
+    android:height="17dp"
+    android:viewportWidth="22"
+    android:viewportHeight="17">
 
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M6.18,13.3h0.95v0.88H6.18v1.98H5.14v-1.98H1.92v-0.64l3.17-5.91h1.09V13.3z M3.07,13.3h2.07V9.25L3.07,13.3z" />
+        android:pathData="M5.32,10.13h1.11v1.03H5.32v2.31H4.11v-2.31H0.35v-0.75l3.7-6.9h1.27V10.13z M1.69,10.13h2.42V5.4L1.69,10.13z" />
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M13.75,15.11l-0.19,0.23c-0.54,0.63-1.33,0.94-2.37,0.94c-0.92,0-1.65-0.31-2.17-0.92s-0.79-1.48-0.8-2.59V11.1 c0-1.2,0.24-2.09,0.72-2.69s1.2-0.89,2.15-0.89c0.81,0,1.45,0.23,1.91,0.68s0.71,1.1,0.76,1.94h-1.07 c-0.04-0.53-0.19-0.95-0.44-1.25s-0.63-0.45-1.14-0.45c-0.61,0-1.06,0.2-1.35,0.6s-0.43,1.04-0.45,1.92v1.74 c0,0.86,0.16,1.52,0.49,1.98s0.8,0.69,1.41,0.69c0.58,0,1.02-0.14,1.32-0.42l0.16-0.15v-1.96h-1.56v-0.92h2.63V15.11z" />
+        android:pathData="M14.15,12.24l-0.22,0.27c-0.63,0.73-1.55,1.1-2.76,1.1c-1.08,0-1.92-0.36-2.53-1.07c-0.61-0.71-0.93-1.72-0.94-3.02V7.56 c0-1.39,0.28-2.44,0.84-3.13s1.39-1.04,2.51-1.04c0.95,0,1.69,0.26,2.23,0.79s0.83,1.28,0.89,2.26H12.9 c-0.05-0.62-0.22-1.1-0.52-1.45s-0.74-0.52-1.34-0.52c-0.72,0-1.24,0.23-1.57,0.7S8.97,6.37,8.96,7.4v2.03 c0,1,0.19,1.77,0.57,2.31c0.38,0.54,0.93,0.8,1.65,0.8c0.67,0,1.19-0.16,1.54-0.49l0.18-0.17V9.59h-1.82V8.52h3.07V12.24z" />
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M 20 9.64 L 18 9.64 L 18 7.64 L 17 7.64 L 17 9.64 L 15 9.64 L 15 10.64 L 17 10.64 L 17 12.64 L 18 12.64 L 18 10.64 L 20 10.64 Z" />
+        android:pathData="M 19.3 5.74 L 19.3 3.39 L 18 3.39 L 18 5.74 L 15.65 5.74 L 15.65 7.04 L 18 7.04 L 18 9.39 L 19.3 9.39 L 19.3 7.04 L 21.65 7.04 L 21.65 5.74 Z" />
     <path
-        android:pathData="M 0 0 H 20 V 24 H 0 V 0 Z" />
+        android:pathData="M 0 0 H 22 V 17 H 0 V 0 Z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_e_mobiledata.xml b/packages/SystemUI/res/drawable/ic_e_mobiledata.xml
index 1a4a2e3..ca601d6 100644
--- a/packages/SystemUI/res/drawable/ic_e_mobiledata.xml
+++ b/packages/SystemUI/res/drawable/ic_e_mobiledata.xml
@@ -14,14 +14,14 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="7dp"
-        android:height="24dp"
-        android:viewportWidth="7"
-        android:viewportHeight="24">
+    android:width="6dp"
+    android:height="17dp"
+    android:viewportWidth="6"
+    android:viewportHeight="17">
 
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M6.5,12.32H3.48v3.02H7v0.92H2.41V7.73h4.53v0.92H3.48v2.75H6.5V12.32z" />
+        android:pathData="M5.1,8.88H1.57v3.53h4.1v1.07H0.32V3.52h5.28V4.6H1.57V7.8H5.1V8.88z" />
     <path
-        android:pathData="M 0 0 H 7 V 24 H 0 V 0 Z" />
+        android:pathData="M 0 0 H 6 V 17 H 0 V 0 Z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_g_mobiledata.xml b/packages/SystemUI/res/drawable/ic_g_mobiledata.xml
index d6a0488..8ff6d7a 100644
--- a/packages/SystemUI/res/drawable/ic_g_mobiledata.xml
+++ b/packages/SystemUI/res/drawable/ic_g_mobiledata.xml
@@ -14,14 +14,14 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="8dp"
-        android:height="24dp"
-        android:viewportWidth="8"
-        android:viewportHeight="24">
+    android:width="7dp"
+    android:height="17dp"
+    android:viewportWidth="7"
+    android:viewportHeight="17">
 
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M8,15.21l-0.19,0.23c-0.54,0.63-1.33,0.94-2.37,0.94c-0.92,0-1.65-0.31-2.17-0.92s-0.79-1.48-0.81-2.59V11.2 c0-1.2,0.24-2.09,0.72-2.69s1.19-0.89,2.15-0.89c0.81,0,1.45,0.23,1.91,0.68S7.95,9.39,8,10.23H6.93C6.88,9.7,6.74,9.28,6.49,8.99 S5.85,8.54,5.34,8.54c-0.61,0-1.06,0.2-1.35,0.6s-0.43,1.04-0.45,1.92v1.74c0,0.86,0.16,1.52,0.49,1.98s0.8,0.69,1.41,0.69 c0.58,0,1.02-0.14,1.32-0.42l0.16-0.15v-1.96H5.37v-0.92H8V15.21z" />
+        android:pathData="M6.73,12.24l-0.22,0.27c-0.63,0.73-1.55,1.1-2.76,1.1c-1.08,0-1.92-0.36-2.53-1.07c-0.61-0.71-0.93-1.72-0.94-3.02V7.56 c0-1.39,0.28-2.44,0.84-3.13S2.5,3.39,3.62,3.39c0.95,0,1.69,0.26,2.23,0.79s0.83,1.28,0.89,2.26H5.48 c-0.05-0.62-0.22-1.1-0.52-1.45S4.22,4.46,3.62,4.46c-0.72,0-1.24,0.23-1.57,0.7S1.54,6.37,1.53,7.4v2.03c0,1,0.19,1.77,0.57,2.31 c0.38,0.54,0.93,0.8,1.65,0.8c0.67,0,1.19-0.16,1.54-0.49l0.18-0.17V9.59H3.66V8.52h3.07V12.24z" />
     <path
-        android:pathData="M 0 0 H 8 V 24 H 0 V 0 Z" />
+        android:pathData="M 0 0 H 7 V 17 H 0 V 0 Z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_h_mobiledata.xml b/packages/SystemUI/res/drawable/ic_h_mobiledata.xml
index be85bbb..68ea58e 100644
--- a/packages/SystemUI/res/drawable/ic_h_mobiledata.xml
+++ b/packages/SystemUI/res/drawable/ic_h_mobiledata.xml
@@ -14,14 +14,14 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="8dp"
-        android:height="24dp"
-        android:viewportWidth="8"
-        android:viewportHeight="24">
+    android:width="7dp"
+    android:height="17dp"
+    android:viewportWidth="7"
+    android:viewportHeight="17">
 
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M8,16.27H6.92v-3.94H3.49v3.94H2.42V7.73h1.07v3.67h3.43V7.73H8V16.27z" />
+        android:pathData="M6.76,13.48H5.5v-4.6H1.49v4.6H0.24V3.52h1.25V7.8H5.5V3.52h1.26V13.48z" />
     <path
-        android:pathData="M 0 0 H 8 V 24 H 0 V 0 Z" />
+        android:pathData="M 0 0 H 7 V 17 H 0 V 0 Z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_h_plus_mobiledata.xml b/packages/SystemUI/res/drawable/ic_h_plus_mobiledata.xml
index f31f83c..42128002 100644
--- a/packages/SystemUI/res/drawable/ic_h_plus_mobiledata.xml
+++ b/packages/SystemUI/res/drawable/ic_h_plus_mobiledata.xml
@@ -14,17 +14,17 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="14dp"
-        android:height="24dp"
-        android:viewportWidth="14"
-        android:viewportHeight="24">
+    android:width="15dp"
+    android:height="17dp"
+    android:viewportWidth="15"
+    android:viewportHeight="17">
 
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M7.64,16.27H6.56v-3.94H3.13v3.94H2.06V7.73h1.07v3.67h3.43V7.73h1.08V16.27z" />
+        android:pathData="M7.01,13.48H5.75v-4.6H1.74v4.6H0.49V3.52h1.25V7.8h4.01V3.52h1.26V13.48z" />
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M 14 9.73 L 12 9.73 L 12 7.73 L 11 7.73 L 11 9.73 L 9 9.73 L 9 10.73 L 11 10.73 L 11 12.73 L 12 12.73 L 12 10.73 L 14 10.73 Z" />
+        android:pathData="M 12.16 5.74 L 12.16 3.39 L 10.86 3.39 L 10.86 5.74 L 8.51 5.74 L 8.51 7.04 L 10.86 7.04 L 10.86 9.39 L 12.16 9.39 L 12.16 7.04 L 14.51 7.04 L 14.51 5.74 Z" />
     <path
-        android:pathData="M 0 0 H 14 V 24 H 0 V 0 Z" />
+        android:pathData="M 0 0 H 15 V 17 H 0 V 0 Z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_lte_mobiledata.xml b/packages/SystemUI/res/drawable/ic_lte_mobiledata.xml
index e45b5e0..7536f51 100644
--- a/packages/SystemUI/res/drawable/ic_lte_mobiledata.xml
+++ b/packages/SystemUI/res/drawable/ic_lte_mobiledata.xml
@@ -14,20 +14,20 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="18dp"
-        android:height="24dp"
-        android:viewportWidth="18"
-        android:viewportHeight="24">
+    android:width="18dp"
+    android:height="17dp"
+    android:viewportWidth="18"
+    android:viewportHeight="17">
 
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M3.79,15.35h3.35v0.92H2.71V7.73h1.08V15.35z" />
+        android:pathData="M1.34,12.4h3.9v1.07H0.08V3.52h1.26V12.4z" />
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M12.15,8.65H9.91v7.61H8.84V8.65H6.6V7.73h5.55V8.65z" />
+        android:pathData="M11.1,4.6H8.48v8.88H7.23V4.6H4.62V3.52h6.48V4.6z" />
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M17.5,12.32h-3.02v3.02H18v0.92h-4.59V7.73h4.53v0.92h-3.46v2.75h3.02V12.32z" />
+        android:pathData="M17.34,8.88h-3.52v3.53h4.1v1.07h-5.35V3.52h5.28V4.6h-4.03V7.8h3.52V8.88z" />
     <path
-        android:pathData="M 0 0 H 18 V 24 H 0 V 0 Z" />
+        android:pathData="M 0 0 H 18 V 17 H 0 V 0 Z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_lte_plus_mobiledata.xml b/packages/SystemUI/res/drawable/ic_lte_plus_mobiledata.xml
index 553a5bd..302e3bd 100644
--- a/packages/SystemUI/res/drawable/ic_lte_plus_mobiledata.xml
+++ b/packages/SystemUI/res/drawable/ic_lte_plus_mobiledata.xml
@@ -14,23 +14,23 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24"
-        android:viewportHeight="24">
+    android:width="26dp"
+    android:height="17dp"
+    android:viewportWidth="26"
+    android:viewportHeight="17">
 
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M3.91,15.35h3.35v0.92H2.84V7.73h1.08V15.35z" />
+        android:pathData="M1.59,12.4h3.9v1.07H0.33V3.52h1.26V12.4z" />
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M12.28,8.65h-2.24v7.61H8.96V8.65H6.73V7.73h5.55V8.65z" />
+        android:pathData="M11.35,4.6H8.73v8.88H7.48V4.6H4.87V3.52h6.48V4.6z" />
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M17.63,12.32h-3.02v3.02h3.52v0.92h-4.59V7.73h4.53v0.92h-3.46v2.75h3.02V12.32z" />
+        android:pathData="M17.59,8.88h-3.52v3.53h4.1v1.07h-5.35V3.52h5.28V4.6h-4.03V7.8h3.52V8.88z" />
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M 24 9.76 L 22 9.76 L 22 7.76 L 21 7.76 L 21 9.76 L 19 9.76 L 19 10.76 L 21 10.76 L 21 12.76 L 22 12.76 L 22 10.76 L 24 10.76 Z" />
+        android:pathData="M 23.32 5.74 L 23.32 3.39 L 22.02 3.39 L 22.02 5.74 L 19.67 5.74 L 19.67 7.04 L 22.02 7.04 L 22.02 9.39 L 23.32 9.39 L 23.32 7.04 L 25.67 7.04 L 25.67 5.74 Z" />
     <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+        android:pathData="M 0 0 H 26 V 17 H 0 V 0 Z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/rounded_full_bg_bottom.xml b/packages/SystemUI/res/drawable/rounded_full_bg_bottom.xml
index c3e36f2..a4b3c99 100644
--- a/packages/SystemUI/res/drawable/rounded_full_bg_bottom.xml
+++ b/packages/SystemUI/res/drawable/rounded_full_bg_bottom.xml
@@ -1,4 +1,18 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
     <solid android:color="?android:attr/colorPrimaryDark" />
diff --git a/packages/SystemUI/res/drawable/rounded_ripple.xml b/packages/SystemUI/res/drawable/rounded_ripple.xml
new file mode 100644
index 0000000..5588eb2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/rounded_ripple.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        android:color="?android:attr/colorControlHighlight">
+    <item android:id="@android:id/mask">
+        <shape xmlns:android="http://schemas.android.com/apk/res/android">
+            <solid android:color="#FFFFFFFF"/>
+            <corners android:radius="8dp"/>
+        </shape>
+    </item>
+    <item android:id="@android:id/background">
+        <shape android:shape="rectangle">
+            <solid android:color="#FFFFFFFF"/>
+            <corners android:radius="8dp"/>
+        </shape>
+    </item>
+</ripple>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_roaming.xml b/packages/SystemUI/res/drawable/stat_sys_roaming.xml
index bd2edf3..0dd9f5a 100644
--- a/packages/SystemUI/res/drawable/stat_sys_roaming.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_roaming.xml
@@ -1,28 +1,27 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+     Copyright (C) 2018 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
 
-         http://www.apache.org/licenses/LICENSE-2.0
+          http://www.apache.org/licenses/LICENSE-2.0
 
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="@dimen/signal_icon_size"
         android:height="@dimen/signal_icon_size"
-        android:viewportWidth="24"
-        android:viewportHeight="24">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M7.8,7.2L9,10H7L5.87,7.33H4V10H2V2h5c1.13,0,2,0.87,2,2v1.33C9,6.13,8.47,6.87,7.8,7.2z M7,4H4v1.33h3V4z" />
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:pathData="M0,0h24v24H0V0z" />
-</vector>
\ No newline at end of file
+        android:viewportWidth="17"
+        android:viewportHeight="17">
+
+<path
+    android:fillColor="#FFFFFFFF"
+    android:pathData="M2.93,4.81H1.81V7.4H1V1h1.79c0.63,0,1.1,0.16,1.42,0.49S4.7,2.29,4.7,2.92c0,0.4-0.09,0.74-0.26,1.04 C4.26,4.25,4.02,4.48,3.7,4.63l1.24,2.72V7.4H4.07L2.93,4.81z M1.81,4.12h0.98c0.34,0,0.61-0.11,0.81-0.33 c0.2-0.22,0.3-0.51,0.3-0.87c0-0.82-0.37-1.23-1.12-1.23H1.81V4.12z" />
+<path
+    android:pathData="M 0 0 H 17 V 17 H 0 V 0 Z" />
+</vector>
diff --git a/packages/SystemUI/res/layout/car_volume_dialog.xml b/packages/SystemUI/res/layout/car_volume_dialog.xml
index e45c0f9..94cc001 100644
--- a/packages/SystemUI/res/layout/car_volume_dialog.xml
+++ b/packages/SystemUI/res/layout/car_volume_dialog.xml
@@ -38,7 +38,7 @@
             android:orientation="vertical"
             android:clipChildren="false"
             android:clipToPadding="false"
-            android:elevation="@dimen/volume_panel_elevation" >
+            android:elevation="@dimen/volume_dialog_elevation" >
             <LinearLayout
                 android:id="@+id/car_volume_dialog_rows"
                 android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml
index cc6e3bf..5ecd380 100644
--- a/packages/SystemUI/res/layout/mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/mobile_signal_group.xml
@@ -50,7 +50,8 @@
         android:layout_height="wrap_content"
         android:layout_width="wrap_content"
         android:layout_gravity="center_vertical"
-        android:paddingEnd="1dp"
+        android:paddingStart="1dp"
+        android:paddingEnd="2dp"
         android:visibility="gone" />
     <Space
         android:id="@+id/mobile_roaming_space"
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index ca8fcba..ed18dc7 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -22,6 +22,7 @@
     android:layout_width="match_parent"
     android:layout_height="@*android:dimen/quick_qs_total_height"
     android:layout_gravity="@integer/notification_panel_layout_gravity"
+    android:background="@android:color/transparent"
     android:baselineAligned="false"
     android:clickable="false"
     android:clipChildren="false"
diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
index 388b633..f38129f 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
@@ -31,23 +31,25 @@
 
     <com.android.systemui.statusbar.policy.Clock
         android:id="@+id/clock"
+        android:textAppearance="@style/TextAppearance.StatusBar.Clock"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
-        android:gravity="center_vertical|start"
+        android:singleLine="true"
         android:paddingStart="@dimen/status_bar_left_clock_starting_padding"
         android:paddingEnd="@dimen/status_bar_left_clock_end_padding"
-        android:singleLine="true"
-        android:textAppearance="@style/TextAppearance.StatusBar.Clock"
-        systemui:showDark="false" />
+        android:gravity="center_vertical|start"
+        systemui:showDark="false"
+    />
 
     <com.android.systemui.statusbar.policy.DateView
         android:id="@+id/date"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:gravity="center_vertical"
+        android:padding="4dp"
         android:singleLine="true"
         android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
         android:textSize="@dimen/qs_time_collapsed_size"
+        android:gravity="center_vertical"
         systemui:datePattern="@string/abbrev_wday_month_day_no_year_alarm" />
 
     <android.widget.Space
@@ -55,11 +57,12 @@
         android:layout_width="0dp"
         android:layout_height="match_parent"
         android:layout_weight="1"
-        android:gravity="center_vertical|center_horizontal" />
+        android:gravity="center_vertical|center_horizontal"
+    />
 
-    <com.android.systemui.BatteryMeterView
-        android:id="@+id/battery"
+    <com.android.systemui.BatteryMeterView android:id="@+id/battery"
         android:layout_height="match_parent"
         android:layout_width="wrap_content"
-        android:gravity="center_vertical|end" />
+        android:gravity="center_vertical|end"
+        />
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 0a3f4eb..d4fe1c6 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -17,9 +17,11 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
+    android:padding="@dimen/volume_dialog_panel_transparent_padding"
     android:background="@android:color/transparent"
     android:theme="@style/qs_theme"
-    android:clipChildren="false" >
+    android:clipChildren="false"
+    android:clipToPadding="false">
     <!-- right-aligned to be physically near volume button -->
     <LinearLayout
         android:id="@+id/volume_dialog"
@@ -30,22 +32,25 @@
         android:background="@android:color/transparent"
         android:layout_margin="@dimen/volume_dialog_base_margin"
         android:orientation="vertical"
-        android:clipChildren="false" >
+        android:clipChildren="false"
+        android:clipToPadding="false" >
 
         <FrameLayout
             android:id="@+id/ringer"
             android:layout_width="@dimen/volume_dialog_ringer_size"
             android:layout_height="@dimen/volume_dialog_ringer_size"
             android:layout_marginBottom="@dimen/volume_dialog_spacer"
-            android:elevation="@dimen/volume_panel_elevation"
+            android:translationZ="@dimen/volume_dialog_elevation"
             android:layout_gravity="right"
+            android:clipChildren="false"
+            android:clipToPadding="false"
             android:background="@drawable/rounded_bg_full">
             <com.android.keyguard.AlphaOptimizedImageButton
                 android:id="@+id/ringer_icon"
                 style="@style/VolumeButtons"
-                android:background="?android:selectableItemBackgroundBorderless"
-                android:layout_width="@dimen/volume_dialog_tap_target_size"
-                android:layout_height="@dimen/volume_dialog_tap_target_size"
+                android:background="@drawable/rounded_ripple"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
                 android:tint="@color/accent_tint_color_selector"
                 android:layout_gravity="center"
                 android:soundEffectsEnabled="false" />
@@ -59,10 +64,10 @@
             android:minWidth="@dimen/volume_dialog_panel_width"
             android:layout_height="wrap_content"
             android:orientation="vertical"
+            android:translationZ="@dimen/volume_dialog_elevation"
             android:clipChildren="false"
             android:clipToPadding="false"
-            android:background="@drawable/rounded_bg_full"
-            android:elevation="@dimen/volume_panel_elevation" >
+            android:background="@drawable/rounded_bg_full" >
             <LinearLayout
                 android:id="@+id/volume_dialog_rows"
                 android:layout_width="wrap_content"
@@ -84,7 +89,7 @@
                     android:layout_height="@dimen/volume_dialog_tap_target_size"
                     android:layout_gravity="center"
                     android:contentDescription="@string/accessibility_volume_settings"
-                    android:background="?android:selectableItemBackgroundBorderless"
+                    android:background="@drawable/ripple_drawable_20dp"
                     android:tint="?android:attr/colorControlNormal"
                     android:soundEffectsEnabled="false" />
             </FrameLayout>
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index bcc3692..6128da8 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -60,7 +60,7 @@
             style="@style/VolumeButtons"
             android:layout_width="@dimen/volume_dialog_tap_target_size"
             android:layout_height="@dimen/volume_dialog_tap_target_size"
-            android:background="?android:selectableItemBackgroundBorderless"
+            android:background="@drawable/ripple_drawable_20dp"
             android:layout_marginBottom="@dimen/volume_dialog_row_margin_bottom"
             android:tint="@color/accent_tint_color_selector"
             android:soundEffectsEnabled="false" />
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 91c8724..0f07ca4 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -270,13 +270,15 @@
     <!-- The width of the panel that holds the quick settings. -->
     <dimen name="qs_panel_width">@dimen/notification_panel_width</dimen>
 
+    <dimen name="volume_dialog_panel_transparent_padding">8dp</dimen>
+
     <!-- the amount the volume panel should be offset at the end from the view next to it (or
     the screen edge, in portrait-->
     <dimen name="volume_dialog_base_margin">8dp</dimen>
 
     <dimen name="volume_dialog_panel_width">64dp</dimen>
 
-    <dimen name="volume_dialog_slider_height">108dp</dimen>
+    <dimen name="volume_dialog_slider_height">116dp</dimen>
 
     <dimen name="volume_dialog_row_height">252dp</dimen>
 
@@ -286,7 +288,7 @@
 
     <dimen name="volume_dialog_spacer">4dp</dimen>
 
-    <dimen name="volume_dialog_slider_margin_top">22dp</dimen>
+    <dimen name="volume_dialog_slider_margin_top">14dp</dimen>
 
     <dimen name="volume_dialog_slider_margin_bottom">-2dp</dimen>
 
@@ -294,6 +296,8 @@
 
     <dimen name="volume_dialog_settings_icon_size">16dp</dimen>
 
+    <dimen name="volume_dialog_elevation">9dp</dimen>
+
     <!-- Gravity for the notification panel -->
     <integer name="notification_panel_layout_gravity">0x31</integer><!-- center_horizontal|top -->
 
@@ -734,8 +738,6 @@
     <dimen name="volume_expander_margin_end">2dp</dimen>
     <dimen name="volume_expander_margin_top">6dp</dimen>
 
-    <dimen name="volume_panel_elevation">8dp</dimen>
-
     <!-- Padding between icon and text for managed profile toast -->
     <dimen name="managed_profile_toast_padding">4dp</dimen>
 
diff --git a/packages/SystemUI/res/values/dimens_car.xml b/packages/SystemUI/res/values/dimens_car.xml
index 5679dd2..6caed61 100644
--- a/packages/SystemUI/res/values/dimens_car.xml
+++ b/packages/SystemUI/res/values/dimens_car.xml
@@ -32,6 +32,8 @@
 
     <dimen name="car_navigation_button_width">64dp</dimen>
     <dimen name="car_navigation_bar_width">760dp</dimen>
+    <dimen name="car_left_navigation_bar_width">96dp</dimen>
+    <dimen name="car_right_navigation_bar_width">96dp</dimen>
 
     <dimen name="car_page_indicator_dot_diameter">12dp</dimen>
     <dimen name="car_page_indicator_margin_bottom">24dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 0320816..4074042 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1350,7 +1350,7 @@
 
     <string name="volume_dialog_title">%s volume controls</string>
 
-    <string name="volume_dialog_ringer_guidance_ring">Calls and notifications will ring</string>
+    <string name="volume_dialog_ringer_guidance_ring">Calls and notifications will ring (<xliff:g id="volume level" example="56">%1$s</xliff:g>)</string>
 
     <string name="output_title">Media output</string>
     <string name="output_calls_title">Phone call output</string>
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 0683514..1ae06d7 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -81,14 +81,6 @@
     private float mDarkIntensity;
     private int mUser;
 
-    /**
-     * Whether we should use colors that adapt based on wallpaper/the scrim behind quick settings.
-     */
-    private boolean mUseWallpaperTextColors;
-
-    private int mNonAdaptedForegroundColor;
-    private int mNonAdaptedBackgroundColor;
-
     public BatteryMeterView(Context context) {
         this(context, null, 0);
     }
@@ -148,29 +140,6 @@
         updateShowPercent();
     }
 
-    /**
-     * Sets whether the battery meter view uses the wallpaperTextColor. If we're not using it, we'll
-     * revert back to dark-mode-based/tinted colors.
-     *
-     * @param shouldUseWallpaperTextColor whether we should use wallpaperTextColor for all
-     *                                    components
-     */
-    public void useWallpaperTextColor(boolean shouldUseWallpaperTextColor) {
-        if (shouldUseWallpaperTextColor == mUseWallpaperTextColors) {
-            return;
-        }
-
-        mUseWallpaperTextColors = shouldUseWallpaperTextColor;
-
-        if (mUseWallpaperTextColors) {
-            updateColors(
-                    Utils.getColorAttr(mContext, R.attr.wallpaperTextColor),
-                    Utils.getColorAttr(mContext, R.attr.wallpaperTextColorSecondary));
-        } else {
-            updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor);
-        }
-    }
-
     public void setColorsFromContext(Context context) {
         if (context == null) {
             return;
@@ -210,8 +179,7 @@
         getContext().getContentResolver().registerContentObserver(
                 Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver, mUser);
         updateShowPercent();
-        Dependency.get(TunerService.class)
-                .addTunable(this, StatusBarIconController.ICON_BLACKLIST);
+        Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
         Dependency.get(ConfigurationController.class).addCallback(this);
         mUserTracker.startTracking();
     }
@@ -305,23 +273,19 @@
     @Override
     public void onDarkChanged(Rect area, float darkIntensity, int tint) {
         mDarkIntensity = darkIntensity;
-
         float intensity = DarkIconDispatcher.isInArea(area, this) ? darkIntensity : 0;
-        mNonAdaptedForegroundColor = getColorForDarkIntensity(
-                intensity, mLightModeFillColor, mDarkModeFillColor);
-        mNonAdaptedBackgroundColor = getColorForDarkIntensity(
-                intensity, mLightModeBackgroundColor,mDarkModeBackgroundColor);
-
-        if (!mUseWallpaperTextColors) {
-            updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor);
-        }
+        int foreground = getColorForDarkIntensity(intensity, mLightModeFillColor,
+                mDarkModeFillColor);
+        int background = getColorForDarkIntensity(intensity, mLightModeBackgroundColor,
+                mDarkModeBackgroundColor);
+        mDrawable.setColors(foreground, background);
+        setTextColor(foreground);
     }
 
-    private void updateColors(int foregroundColor, int backgroundColor) {
-        mDrawable.setColors(foregroundColor, backgroundColor);
-        mTextColor = foregroundColor;
+    public void setTextColor(int color) {
+        mTextColor = color;
         if (mBatteryPercentView != null) {
-            mBatteryPercentView.setTextColor(foregroundColor);
+            mBatteryPercentView.setTextColor(color);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index 816c598..8cff56d 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -228,9 +228,14 @@
         mHandler.removeCallbacks(mConnectionRunnable);
         Intent launcherServiceIntent = new Intent(ACTION_QUICKSTEP)
                 .setPackage(mRecentsComponentName.getPackageName());
-        boolean bound = mContext.bindServiceAsUser(launcherServiceIntent,
-                mOverviewServiceConnection, Context.BIND_AUTO_CREATE,
-                UserHandle.of(mDeviceProvisionedController.getCurrentUser()));
+        boolean bound = false;
+        try {
+            bound = mContext.bindServiceAsUser(launcherServiceIntent,
+                    mOverviewServiceConnection, Context.BIND_AUTO_CREATE,
+                    UserHandle.of(mDeviceProvisionedController.getCurrentUser()));
+        } catch (SecurityException e) {
+            Log.e(TAG_OPS, "Unable to bind because of security error", e);
+        }
         if (!bound) {
             // Retry after exponential backoff timeout
             final long timeoutMs = (long) Math.scalb(BACKOFF_MILLIS, mConnectionBackoffAttempts);
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 1a9655e..2a27147 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -53,7 +53,8 @@
             Key.NUM_APPS_LAUNCHED,
             Key.HAS_SEEN_RECENTS_ONBOARDING,
             Key.SEEN_RINGER_GUIDANCE_COUNT,
-            Key.QS_HAS_TURNED_OFF_MOBILE_DATA
+            Key.QS_HAS_TURNED_OFF_MOBILE_DATA,
+            Key.TOUCHED_RINGER_TOGGLE
     })
     public @interface Key {
         @Deprecated
@@ -91,6 +92,7 @@
         String SEEN_RINGER_GUIDANCE_COUNT = "RingerGuidanceCount";
         String QS_TILE_SPECS_REVEALED = "QsTileSpecsRevealed";
         String QS_HAS_TURNED_OFF_MOBILE_DATA = "QsHasTurnedOffMobileData";
+        String TOUCHED_RINGER_TOGGLE = "TouchedRingerToggle";
     }
 
     public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 2c0e95b..a61ce8c 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -29,30 +29,16 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.util.ArraySet;
-import android.util.TimingsTraceLog;
 import android.util.Log;
+import android.util.TimingsTraceLog;
 
-import com.android.systemui.globalactions.GlobalActionsComponent;
-import com.android.systemui.keyboard.KeyboardUI;
-import com.android.systemui.keyguard.KeyguardViewMediator;
-import com.android.systemui.media.RingtonePlayer;
-import com.android.systemui.pip.PipUI;
 import com.android.systemui.plugins.OverlayPlugin;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.PluginManager;
-import com.android.systemui.power.PowerUI;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.shortcut.ShortcutKeyDispatcher;
-import com.android.systemui.stackdivider.Divider;
-import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarWindowManager;
-import com.android.systemui.usb.StorageNotification;
 import com.android.systemui.util.NotificationChannels;
-import com.android.systemui.util.leak.GarbageMonitor;
-import com.android.systemui.volume.VolumeUI;
 
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -99,6 +85,10 @@
                             mServices[i].onBootCompleted();
                         }
                     }
+
+                    IntentFilter localeChangedFilter = new IntentFilter(
+                            Intent.ACTION_LOCALE_CHANGED);
+                    registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
                 }
             }, filter);
         } else {
@@ -249,4 +239,14 @@
     public SystemUI[] getServices() {
         return mServices;
     }
+
+    private final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
+                // Update names of SystemUi notification channels
+                NotificationChannels.createAll(context);
+            }
+        }
+    };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 7161463..bfbfbf6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -18,15 +18,17 @@
 
 import android.content.Context;
 import android.content.res.Configuration;
+import android.graphics.Canvas;
+import android.graphics.Path;
 import android.graphics.Point;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.View;
 import android.widget.FrameLayout;
 
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
 import com.android.systemui.qs.customize.QSCustomizer;
+import com.android.systemui.statusbar.ExpandableOutlineView;
 
 /**
  * Wrapper view with background which contains {@link QSPanel} and {@link BaseStatusBarHeader}
@@ -42,11 +44,7 @@
     protected float mQsExpansion;
     private QSCustomizer mQSCustomizer;
     private View mQSFooter;
-
     private View mBackground;
-    private View mBackgroundGradient;
-    private View mStatusBarBackground;
-
     private int mSideMargins;
 
     public QSContainerImpl(Context context, AttributeSet attrs) {
@@ -62,8 +60,6 @@
         mQSCustomizer = findViewById(R.id.qs_customize);
         mQSFooter = findViewById(R.id.qs_footer);
         mBackground = findViewById(R.id.quick_settings_background);
-        mStatusBarBackground = findViewById(R.id.quick_settings_status_bar_background);
-        mBackgroundGradient = findViewById(R.id.quick_settings_gradient_view);
         mSideMargins = getResources().getDimensionPixelSize(R.dimen.notification_side_paddings);
 
         setClickable(true);
@@ -72,22 +68,6 @@
     }
 
     @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-
-        // Hide the backgrounds when in landscape mode.
-        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
-            mBackgroundGradient.setVisibility(View.INVISIBLE);
-            mStatusBarBackground.setVisibility(View.INVISIBLE);
-        } else {
-            mBackgroundGradient.setVisibility(View.VISIBLE);
-            mStatusBarBackground.setVisibility(View.VISIBLE);
-        }
-
-        updateResources();
-    }
-
-    @Override
     public boolean performClick() {
         // Want to receive clicks so missing QQS tiles doesn't cause collapse, but
         // don't want to do anything with them.
@@ -121,14 +101,6 @@
         updateExpansion();
     }
 
-    private void updateResources() {
-        LayoutParams layoutParams = (LayoutParams) mQSPanel.getLayoutParams();
-        layoutParams.topMargin = mContext.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.quick_qs_offset_height);
-
-        mQSPanel.setLayoutParams(layoutParams);
-    }
-
     /**
      * Overrides the height of this view (post-layout), so that the content is clipped to that
      * height and the background is set to that height.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index ca88d70..0ac8b9c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -26,7 +26,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.media.AudioManager;
@@ -56,10 +55,8 @@
 import com.android.systemui.statusbar.phone.PhoneStatusBarView;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
-import com.android.systemui.statusbar.policy.Clock;
 import com.android.systemui.statusbar.policy.DarkIconDispatcher;
 import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.statusbar.policy.DateView;
 import com.android.systemui.statusbar.policy.NextAlarmController;
 
 import java.util.Locale;
@@ -94,7 +91,6 @@
     private TouchAnimator mStatusIconsAlphaAnimator;
     private TouchAnimator mHeaderTextContainerAlphaAnimator;
 
-    private View mSystemIconsView;
     private View mQuickQsStatusIcons;
     private View mDate;
     private View mHeaderTextContainerView;
@@ -112,9 +108,6 @@
     private View mStatusSeparator;
     private ImageView mRingerModeIcon;
     private TextView mRingerModeTextView;
-    private BatteryMeterView mBatteryMeterView;
-    private Clock mClockView;
-    private DateView mDateView;
 
     private NextAlarmController mAlarmController;
     /** Counts how many times the long press tooltip has been shown to the user. */
@@ -146,7 +139,6 @@
         mHeaderQsPanel = findViewById(R.id.quick_qs_panel);
         mDate = findViewById(R.id.date);
         mDate.setOnClickListener(this);
-        mSystemIconsView = findViewById(R.id.quick_status_bar_system_icons);
         mQuickQsStatusIcons = findViewById(R.id.quick_qs_status_icons);
         mIconManager = new TintedIconManager(findViewById(R.id.statusIcons));
 
@@ -174,10 +166,8 @@
         // Set the correct tint for the status icons so they contrast
         mIconManager.setTint(fillColor);
 
-        mBatteryMeterView = findViewById(R.id.battery);
-        mBatteryMeterView.setForceShowPercent(true);
-        mClockView = findViewById(R.id.clock);
-        mDateView = findViewById(R.id.date);
+        BatteryMeterView battery = findViewById(R.id.battery);
+        battery.setForceShowPercent(true);
     }
 
     private void updateStatusText() {
@@ -224,13 +214,6 @@
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         updateResources();
-
-        // Update color schemes in landscape to use wallpaperTextColor
-        boolean shouldUseWallpaperTextColor =
-                newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE;
-        mBatteryMeterView.useWallpaperTextColor(shouldUseWallpaperTextColor);
-        mClockView.useWallpaperTextColor(shouldUseWallpaperTextColor);
-        mDateView.useWallpaperTextColor(shouldUseWallpaperTextColor);
     }
 
     @Override
@@ -240,21 +223,11 @@
     }
 
     private void updateResources() {
-        Resources resources = mContext.getResources();
-
-        // Update height for a few views, especially due to landscape mode restricting space.
+        // Update height, especially due to landscape mode restricting space.
         mHeaderTextContainerView.getLayoutParams().height =
-                resources.getDimensionPixelSize(R.dimen.qs_header_tooltip_height);
+                mContext.getResources().getDimensionPixelSize(R.dimen.qs_header_tooltip_height);
         mHeaderTextContainerView.setLayoutParams(mHeaderTextContainerView.getLayoutParams());
 
-        mSystemIconsView.getLayoutParams().height = resources.getDimensionPixelSize(
-                com.android.internal.R.dimen.quick_qs_offset_height);
-        mSystemIconsView.setLayoutParams(mSystemIconsView.getLayoutParams());
-
-        getLayoutParams().height =
-                resources.getDimensionPixelSize(com.android.internal.R.dimen.quick_qs_total_height);
-        setLayoutParams(getLayoutParams());
-
         updateStatusIconAlphaAnimator();
         updateHeaderTextContainerAlphaAnimator();
     }
@@ -526,8 +499,9 @@
         mHeaderQsPanel.setHost(host, null /* No customization in header */);
 
         // Use SystemUI context to get battery meter colors, and let it use the default tint (white)
-        mBatteryMeterView.setColorsFromContext(mHost.getContext());
-        mBatteryMeterView.onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
+        BatteryMeterView battery = findViewById(R.id.battery);
+        battery.setColorsFromContext(mHost.getContext());
+        battery.onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
     }
 
     public void setCallback(Callback qsPanelCallback) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java
index 2841136..b7d501e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java
@@ -46,6 +46,12 @@
         }
     }
 
+    public void removeAll() {
+        mButtonsByCategory.clear();
+        mButtonsByPackage.clear();
+        mSelectedFacetButton = null;
+    }
+
     /**
      * This will unselect the currently selected CarFacetButton and determine which one should be
      * selected next. It does this by reading the properties on the CarFacetButton and seeing if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index a95d0a4..3530e0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -45,6 +45,7 @@
 import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 
 import java.io.FileDescriptor;
@@ -80,12 +81,16 @@
     private boolean mShowRight;
     private boolean mShowBottom;
     private CarFacetButtonController mCarFacetButtonController;
+    private ActivityManagerWrapper mActivityManagerWrapper;
+    private DeviceProvisionedController mDeviceProvisionedController;
+    private boolean mDeviceIsProvisioned = true;
 
     @Override
     public void start() {
         super.start();
         mTaskStackListener = new TaskStackListenerImpl();
-        ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
+        mActivityManagerWrapper = ActivityManagerWrapper.getInstance();
+        mActivityManagerWrapper.registerTaskStackListener(mTaskStackListener);
 
         mStackScroller.setScrollingEnabled(true);
 
@@ -96,12 +101,54 @@
             Log.d(TAG, "Connecting to HVAC service");
             Dependency.get(HvacController.class).connectToCarService();
         }
+        mCarFacetButtonController = Dependency.get(CarFacetButtonController.class);
+        mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
+        mDeviceIsProvisioned = mDeviceProvisionedController.isDeviceProvisioned();
+        if (!mDeviceIsProvisioned) {
+            mDeviceProvisionedController.addCallback(
+                    new DeviceProvisionedController.DeviceProvisionedListener() {
+                        @Override
+                        public void onDeviceProvisionedChanged() {
+                            mDeviceIsProvisioned =
+                                    mDeviceProvisionedController.isDeviceProvisioned();
+                            restartNavBars();
+                        }
+                    });
+        }
     }
 
+    /**
+     * Remove all content from navbars and rebuild them. Used to allow for different nav bars
+     * before and after the device is provisioned
+     */
+    private void restartNavBars() {
+        mCarFacetButtonController.removeAll();
+        if (ENABLE_HVAC_CONNECTION) {
+            Dependency.get(HvacController.class).removeAllComponents();
+        }
+        if (mNavigationBarWindow != null) {
+            mNavigationBarWindow.removeAllViews();
+            mNavigationBarView = null;
+        }
+
+        if (mLeftNavigationBarWindow != null) {
+            mLeftNavigationBarWindow.removeAllViews();
+            mLeftNavigationBarView = null;
+        }
+
+        if (mRightNavigationBarWindow != null) {
+            mRightNavigationBarWindow.removeAllViews();
+            mRightNavigationBarView = null;
+        }
+        buildNavBarContent();
+    }
+
+
     @Override
     public void destroy() {
         mCarBatteryController.stopListening();
         mConnectedDeviceSignalController.stopListening();
+        mActivityManagerWrapper.unregisterTaskStackListener(mTaskStackListener);
 
         if (mNavigationBarWindow != null) {
             mWindowManager.removeViewImmediate(mNavigationBarWindow);
@@ -117,10 +164,10 @@
             mWindowManager.removeViewImmediate(mRightNavigationBarWindow);
             mRightNavigationBarView = null;
         }
-
         super.destroy();
     }
 
+
     @Override
     protected void makeStatusBarView() {
         super.makeStatusBarView();
@@ -167,129 +214,132 @@
 
     @Override
     protected void createNavigationBar() {
-        mCarFacetButtonController = Dependency.get(CarFacetButtonController.class);
-        if (mNavigationBarView != null) {
-            return;
-        }
-
         mShowBottom = mContext.getResources().getBoolean(R.bool.config_enableBottomNavigationBar);
-        if (mShowBottom) {
-            buildBottomBar();
-        }
-
-        int widthForSides = mContext.getResources().getDimensionPixelSize(
-                R.dimen.navigation_bar_height_car_mode);
-
-
         mShowLeft = mContext.getResources().getBoolean(R.bool.config_enableLeftNavigationBar);
-
-        if (mShowLeft) {
-            buildLeft(widthForSides);
-        }
-
         mShowRight = mContext.getResources().getBoolean(R.bool.config_enableRightNavigationBar);
 
+        buildNavBarWindows();
+        buildNavBarContent();
+        attachNavBarWindows();
+    }
+
+    private void buildNavBarContent() {
+        if (mShowBottom) {
+            buildBottomBar((mDeviceIsProvisioned) ? R.layout.car_navigation_bar :
+                    R.layout.car_navigation_bar_unprovisioned);
+        }
+
+        if (mShowLeft) {
+            buildLeft((mDeviceIsProvisioned) ? R.layout.car_left_navigation_bar :
+                    R.layout.car_left_navigation_bar_unprovisioned);
+        }
+
         if (mShowRight) {
-            buildRight(widthForSides);
+            buildRight((mDeviceIsProvisioned) ? R.layout.car_right_navigation_bar :
+                    R.layout.car_right_navigation_bar_unprovisioned);
+        }
+    }
+
+    private void buildNavBarWindows() {
+        if (mShowBottom) {
+
+             mNavigationBarWindow = (ViewGroup) View.inflate(mContext,
+                    R.layout.navigation_bar_window, null);
+        }
+        if (mShowLeft) {
+            mLeftNavigationBarWindow = (ViewGroup) View.inflate(mContext,
+                R.layout.navigation_bar_window, null);
+        }
+        if (mShowRight) {
+            mRightNavigationBarWindow = (ViewGroup) View.inflate(mContext,
+                    R.layout.navigation_bar_window, null);
         }
 
     }
 
+    private void attachNavBarWindows() {
 
-    private void buildBottomBar() {
+        if (mShowBottom) {
+            WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                    LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
+                    WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
+                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                            | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                            | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+                            | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+                    PixelFormat.TRANSLUCENT);
+            lp.setTitle("CarNavigationBar");
+            lp.windowAnimations = 0;
+            mWindowManager.addView(mNavigationBarWindow, lp);
+        }
+        if (mShowLeft) {
+            int width = mContext.getResources().getDimensionPixelSize(
+                    R.dimen.car_left_navigation_bar_width);
+            WindowManager.LayoutParams leftlp = new WindowManager.LayoutParams(
+                    width, LayoutParams.MATCH_PARENT,
+                    WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                            | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                            | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+                            | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+                    PixelFormat.TRANSLUCENT);
+            leftlp.setTitle("LeftCarNavigationBar");
+            leftlp.windowAnimations = 0;
+            leftlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
+            leftlp.gravity = Gravity.LEFT;
+            mWindowManager.addView(mLeftNavigationBarWindow, leftlp);
+        }
+        if (mShowRight) {
+            int width = mContext.getResources().getDimensionPixelSize(
+                    R.dimen.car_right_navigation_bar_width);
+            WindowManager.LayoutParams rightlp = new WindowManager.LayoutParams(
+                    width, LayoutParams.MATCH_PARENT,
+                    WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                            | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                            | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+                            | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+                    PixelFormat.TRANSLUCENT);
+            rightlp.setTitle("RightCarNavigationBar");
+            rightlp.windowAnimations = 0;
+            rightlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
+            rightlp.gravity = Gravity.RIGHT;
+            mWindowManager.addView(mRightNavigationBarWindow, rightlp);
+        }
+
+    }
+
+    private void buildBottomBar(int layout) {
         // SystemUI requires that the navigation bar view have a parent. Since the regular
         // StatusBar inflates navigation_bar_window as this parent view, use the same view for the
         // CarNavigationBarView.
-        mNavigationBarWindow = (ViewGroup) View.inflate(mContext,
-                R.layout.navigation_bar_window, null);
-        if (mNavigationBarWindow == null) {
-            Log.e(TAG, "CarStatusBar failed inflate for R.layout.navigation_bar_window");
-        }
-
-
-        View.inflate(mContext, R.layout.car_navigation_bar, mNavigationBarWindow);
+        View.inflate(mContext, layout, mNavigationBarWindow);
         mNavigationBarView = (CarNavigationBarView) mNavigationBarWindow.getChildAt(0);
         if (mNavigationBarView == null) {
             Log.e(TAG, "CarStatusBar failed inflate for R.layout.car_navigation_bar");
             throw new RuntimeException("Unable to build botom nav bar due to missing layout");
         }
         mNavigationBarView.setStatusBar(this);
-
-
-        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
-                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
-                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
-                PixelFormat.TRANSLUCENT);
-        lp.setTitle("CarNavigationBar");
-        lp.windowAnimations = 0;
-
-
-        mWindowManager.addView(mNavigationBarWindow, lp);
     }
 
-    private void buildLeft(int widthForSides) {
-        mLeftNavigationBarWindow = (ViewGroup) View.inflate(mContext,
-                R.layout.navigation_bar_window, null);
-        if (mLeftNavigationBarWindow == null) {
-            Log.e(TAG, "CarStatusBar failed inflate for R.layout.navigation_bar_window");
-        }
-
-        View.inflate(mContext, R.layout.car_left_navigation_bar, mLeftNavigationBarWindow);
+    private void buildLeft(int layout) {
+        View.inflate(mContext, layout, mLeftNavigationBarWindow);
         mLeftNavigationBarView = (CarNavigationBarView) mLeftNavigationBarWindow.getChildAt(0);
         if (mLeftNavigationBarView == null) {
             Log.e(TAG, "CarStatusBar failed inflate for R.layout.car_navigation_bar");
             throw new RuntimeException("Unable to build left nav bar due to missing layout");
         }
         mLeftNavigationBarView.setStatusBar(this);
-
-        WindowManager.LayoutParams leftlp = new WindowManager.LayoutParams(
-                widthForSides, LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
-                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
-                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
-                PixelFormat.TRANSLUCENT);
-        leftlp.setTitle("LeftCarNavigationBar");
-        leftlp.windowAnimations = 0;
-        leftlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
-        leftlp.gravity = Gravity.LEFT;
-        mWindowManager.addView(mLeftNavigationBarWindow, leftlp);
     }
 
 
-    private void buildRight(int widthForSides) {
-        mRightNavigationBarWindow = (ViewGroup) View.inflate(mContext,
-                R.layout.navigation_bar_window, null);
-        if (mRightNavigationBarWindow == null) {
-            Log.e(TAG, "CarStatusBar failed inflate for R.layout.navigation_bar_window");
-        }
-
-        View.inflate(mContext, R.layout.car_right_navigation_bar, mRightNavigationBarWindow);
+    private void buildRight(int layout) {
+        View.inflate(mContext, layout, mRightNavigationBarWindow);
         mRightNavigationBarView = (CarNavigationBarView) mRightNavigationBarWindow.getChildAt(0);
         if (mRightNavigationBarView == null) {
             Log.e(TAG, "CarStatusBar failed inflate for R.layout.car_navigation_bar");
             throw new RuntimeException("Unable to build right nav bar due to missing layout");
         }
-        mRightNavigationBarView.setStatusBar(this);
-
-        WindowManager.LayoutParams rightlp = new WindowManager.LayoutParams(
-                widthForSides, LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
-                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
-                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
-                PixelFormat.TRANSLUCENT);
-        rightlp.setTitle("RightCarNavigationBar");
-        rightlp.windowAnimations = 0;
-        rightlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
-        rightlp.gravity = Gravity.RIGHT;
-        mWindowManager.addView(mRightNavigationBarWindow, rightlp);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java
index 23bf887..7d283d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java
@@ -176,6 +176,14 @@
     };
 
     /**
+     * Removes all registered components. This is useful if you need to rebuild the UI since
+     * components self register.
+     */
+    public void removeAllComponents() {
+        mTempComponents.clear();
+    }
+
+    /**
      * Key for storing {@link TemperatureView}s in a hash map
      */
     private static class HvacKey {
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 fcd4e8f..df2b817 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -334,6 +334,20 @@
         return mKeyguardView != null && mKeyguardView.hasDismissActions();
     }
 
+    public int getTop() {
+        if (mKeyguardView == null) {
+            return 0;
+        }
+
+        int top = mKeyguardView.getTop();
+        // The password view has an extra top padding that should be ignored.
+        if (mKeyguardView.getCurrentSecurityMode() == SecurityMode.Password) {
+            View messageArea = mKeyguardView.findViewById(R.id.keyguard_message_area);
+            top += messageArea.getTop();
+        }
+        return top;
+    }
+
     protected void ensureView() {
         // Removal of the view might be deferred to reduce unlock latency,
         // in this case we need to force the removal, otherwise we'll
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 19e8295..3d7067d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -114,6 +114,11 @@
     private boolean mTracking;
 
     /**
+     * Distance in pixels between the top of the screen and the first view of the bouncer.
+     */
+    private int mBouncerTop;
+
+    /**
      * Refreshes the dimension values.
      */
     public void loadDimens(Resources res) {
@@ -129,7 +134,7 @@
 
     public void setup(int minTopMargin, int maxShadeBottom, int notificationStackHeight,
             float expandedHeight, float maxPanelHeight, int parentHeight, int keyguardStatusHeight,
-            float dark, boolean secure, boolean tracking) {
+            float dark, boolean secure, boolean tracking, int bouncerTop) {
         mMinTopMargin = minTopMargin + mContainerTopPadding;
         mMaxShadeBottom = maxShadeBottom;
         mNotificationStackHeight = notificationStackHeight;
@@ -140,6 +145,7 @@
         mDarkAmount = dark;
         mCurrentlySecure = secure;
         mTracking = tracking;
+        mBouncerTop = bouncerTop;
     }
 
     public void run(Result result) {
@@ -189,8 +195,10 @@
     private int getClockY() {
         // Dark: Align the bottom edge of the clock at about half of the screen:
         final float clockYDark = getMaxClockY() + burnInPreventionOffsetY();
-        float clockYRegular = getExpandedClockPosition();
-        float clockYTarget = mCurrentlySecure ? mMinTopMargin : -mKeyguardStatusHeight;
+        final float clockYRegular = getExpandedClockPosition();
+        final boolean hasEnoughSpace = mMinTopMargin + mKeyguardStatusHeight < mBouncerTop;
+        float clockYTarget = mCurrentlySecure && hasEnoughSpace ?
+                mMinTopMargin : -mKeyguardStatusHeight;
 
         // Move clock up while collapsing the shade
         float shadeExpansion = mExpandedHeight / mMaxPanelHeight;
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 cccda90..27ca0d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -160,6 +160,7 @@
     protected int mQsMinExpansionHeight;
     protected int mQsMaxExpansionHeight;
     private int mQsPeekHeight;
+    private int mBouncerTop;
     private boolean mStackScrollerOverscrolling;
     private boolean mQsExpansionFromOverscroll;
     private float mLastOverscroll;
@@ -476,7 +477,8 @@
                     mKeyguardStatusView.getHeight(),
                     mDarkAmount,
                     mStatusBar.isKeyguardCurrentlySecure(),
-                    mTracking);
+                    mTracking,
+                    mBouncerTop);
             mClockPositionAlgorithm.run(mClockPositionResult);
             if (animate || mClockAnimator != null) {
                 startClockAnimation(mClockPositionResult.clockX, mClockPositionResult.clockY);
@@ -550,6 +552,11 @@
         return count;
     }
 
+    public void setBouncerTop(int bouncerTop) {
+        mBouncerTop = bouncerTop;
+        positionClockAndNotifications();
+    }
+
     private void startClockAnimation(int x, int y) {
         if (mClockAnimationTargetX == x && mClockAnimationTargetY == y) {
             return;
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 4e12936..2c025b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -85,7 +85,7 @@
     /**
      * Default alpha value for most scrims.
      */
-    public static final float GRADIENT_SCRIM_ALPHA = 0.70f;
+    public static final float GRADIENT_SCRIM_ALPHA = 0.45f;
     /**
      * A scrim varies its opacity based on a busyness factor, for example
      * how many notifications are currently visible.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index c03ecb3..beeba83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -562,7 +562,7 @@
     };
 
     private KeyguardUserSwitcher mKeyguardUserSwitcher;
-    private UserSwitcherController mUserSwitcherController;
+    protected UserSwitcherController mUserSwitcherController;
     private NetworkController mNetworkController;
     private KeyguardMonitorImpl mKeyguardMonitor
             = (KeyguardMonitorImpl) Dependency.get(KeyguardMonitor.class);
@@ -588,7 +588,7 @@
         }
     };
     private boolean mNoAnimationOnNextBarModeChange;
-    private FalsingManager mFalsingManager;
+    protected FalsingManager mFalsingManager;
 
     private final KeyguardUpdateMonitorCallback mUpdateCallback =
             new KeyguardUpdateMonitorCallback() {
@@ -3448,6 +3448,13 @@
         return updateIsKeyguard();
     }
 
+    /**
+     * @return True if StatusBar state is FULLSCREEN_USER_SWITCHER.
+     */
+    public boolean isFullScreenUserSwitcherState() {
+        return mState == StatusBarState.FULLSCREEN_USER_SWITCHER;
+    }
+
     private boolean updateIsKeyguard() {
         boolean wakeAndUnlocking = mFingerprintUnlockController.getMode()
                 == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
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 5975608..6b6ea10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -135,26 +135,34 @@
         mFingerprintUnlockController = fingerprintUnlockController;
         mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
                 mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry);
+        mContainer.addOnLayoutChangeListener(this::onContainerLayout);
         mNotificationPanelView = notificationPanelView;
         notificationPanelView.setExpansionListener(this::onPanelExpansionChanged);
     }
 
+    private void onContainerLayout(View v, int left, int top, int right, int bottom,
+            int oldLeft, int oldTop, int oldRight, int oldBottom) {
+        mNotificationPanelView.setBouncerTop(mBouncer.getTop());
+    }
+
     private void onPanelExpansionChanged(float expansion, boolean tracking) {
         // We don't want to translate the bounce when:
         // • Keyguard is occluded, because we're in a FLAG_SHOW_WHEN_LOCKED activity and need to
         //   conserve the original animation.
         // • The user quickly taps on the display and we show "swipe up to unlock."
         // • Keyguard will be dismissed by an action. a.k.a: FLAG_DISMISS_KEYGUARD_ACTIVITY
+        // • Full-screen user switcher is displayed.
         final boolean noLongerTracking = mLastTracking != tracking && !tracking;
         if (mOccluded || mNotificationPanelView.isUnlockHintRunning()
-                || mBouncer.willDismissWithAction()) {
+                || mBouncer.willDismissWithAction()
+                || mStatusBar.isFullScreenUserSwitcherState()) {
             mBouncer.setExpansion(0);
         } else if (mShowing && mStatusBar.isKeyguardCurrentlySecure() && !mDozing) {
             mBouncer.setExpansion(expansion);
             if (expansion == 1) {
                 mBouncer.onFullyHidden();
             } else if (!mBouncer.isShowing() && !mBouncer.isAnimatingAway()) {
-                mBouncer.show(false /* resetSecuritySelection */, false /* notifyFalsing */);
+                mBouncer.show(false /* resetSecuritySelection */, false /* animated */);
             } else if (noLongerTracking) {
                 // Notify that falsing manager should stop its session when user stops touching,
                 // even before the animation ends, to guarantee that we're not recording sensitive
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index baeaaad..4c92d01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -40,7 +40,6 @@
 import android.view.View;
 import android.widget.TextView;
 
-import com.android.settingslib.Utils;
 import com.android.systemui.DemoMode;
 import com.android.systemui.Dependency;
 import com.android.systemui.FontSizeUtils;
@@ -85,17 +84,6 @@
     private boolean mShowSeconds;
     private Handler mSecondsHandler;
 
-    /**
-     * Whether we should use colors that adapt based on wallpaper/the scrim behind quick settings
-     * for text.
-     */
-    private boolean mUseWallpaperTextColor;
-
-    /**
-     * Color to be set on this {@link TextView}, when wallpaperTextColor is <b>not</b> utilized.
-     */
-    private int mNonAdaptedColor;
-
     public Clock(Context context) {
         this(context, null);
     }
@@ -113,7 +101,6 @@
         try {
             mAmPmStyle = a.getInt(R.styleable.Clock_amPmStyle, AM_PM_STYLE_GONE);
             mShowDark = a.getBoolean(R.styleable.Clock_showDark, true);
-            mNonAdaptedColor = getCurrentTextColor();
         } finally {
             a.recycle();
         }
@@ -240,10 +227,7 @@
 
     @Override
     public void onDarkChanged(Rect area, float darkIntensity, int tint) {
-        mNonAdaptedColor = DarkIconDispatcher.getTint(area, this, tint);
-        if (!mUseWallpaperTextColor) {
-            setTextColor(mNonAdaptedColor);
-        }
+        setTextColor(DarkIconDispatcher.getTint(area, this, tint));
     }
 
     @Override
@@ -258,25 +242,6 @@
                 0);
     }
 
-    /**
-     * Sets whether the clock uses the wallpaperTextColor. If we're not using it, we'll revert back
-     * to dark-mode-based/tinted colors.
-     *
-     * @param shouldUseWallpaperTextColor whether we should use wallpaperTextColor for text color
-     */
-    public void useWallpaperTextColor(boolean shouldUseWallpaperTextColor) {
-        if (shouldUseWallpaperTextColor == mUseWallpaperTextColor) {
-            return;
-        }
-        mUseWallpaperTextColor = shouldUseWallpaperTextColor;
-
-        if (mUseWallpaperTextColor) {
-            setTextColor(Utils.getColorAttr(mContext, R.attr.wallpaperTextColor));
-        } else {
-            setTextColor(mNonAdaptedColor);
-        }
-    }
-
     private void updateShowSeconds() {
         if (mShowSeconds) {
             // Wait until we have a display to start trying to show seconds.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
index ef630c7..74a30fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
@@ -27,7 +27,6 @@
 import android.util.AttributeSet;
 import android.widget.TextView;
 
-import com.android.settingslib.Utils;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 
@@ -43,17 +42,6 @@
     private String mLastText;
     private String mDatePattern;
 
-    /**
-     * Whether we should use colors that adapt based on wallpaper/the scrim behind quick settings
-     * for text.
-     */
-    private boolean mUseWallpaperTextColor;
-
-    /**
-     * Color to be set on this {@link TextView}, when wallpaperTextColor is <b>not</b> utilized.
-     */
-    private int mNonAdaptedTextColor;
-
     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -74,7 +62,6 @@
 
     public DateView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mNonAdaptedTextColor = getCurrentTextColor();
         TypedArray a = context.getTheme().obtainStyledAttributes(
                 attrs,
                 R.styleable.DateView,
@@ -130,25 +117,6 @@
         }
     }
 
-    /**
-     * Sets whether the date view uses the wallpaperTextColor. If we're not using it, we'll revert
-     * back to dark-mode-based/tinted colors.
-     *
-     * @param shouldUseWallpaperTextColor whether we should use wallpaperTextColor for text color
-     */
-    public void useWallpaperTextColor(boolean shouldUseWallpaperTextColor) {
-        if (shouldUseWallpaperTextColor == mUseWallpaperTextColor) {
-            return;
-        }
-        mUseWallpaperTextColor = shouldUseWallpaperTextColor;
-
-        if (mUseWallpaperTextColor) {
-            setTextColor(Utils.getColorAttr(mContext, R.attr.wallpaperTextColor));
-        } else {
-            setTextColor(mNonAdaptedTextColor);
-        }
-    }
-
     public void setDatePattern(String pattern) {
         if (TextUtils.equals(pattern, mDatePattern)) {
             return;
diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
index 1cbdfe8..7a9cdfd 100644
--- a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
+++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
@@ -39,8 +39,7 @@
     public static String BATTERY     = "BAT";
     public static String HINTS       = "HNT";
 
-    @VisibleForTesting
-    static void createAll(Context context) {
+    public static void createAll(Context context) {
         final NotificationManager nm = context.getSystemService(NotificationManager.class);
         final NotificationChannel batteryChannel = new NotificationChannel(BATTERY,
                 context.getString(R.string.notification_channel_battery),
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index ee6748e..a97effd 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.volume;
 
+import static android.media.AudioManager.RINGER_MODE_NORMAL;
+
 import android.app.NotificationManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -29,6 +31,7 @@
 import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.AudioSystem;
+import android.media.IAudioService;
 import android.media.IVolumeController;
 import android.media.VolumePolicy;
 import android.media.session.MediaController.PlaybackInfo;
@@ -39,6 +42,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.provider.Settings;
@@ -73,9 +77,11 @@
 public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpable {
     private static final String TAG = Util.logTag(VolumeDialogControllerImpl.class);
 
+
+    private static final int TOUCH_FEEDBACK_TIMEOUT_MS = 1000;
     private static final int DYNAMIC_STREAM_START_INDEX = 100;
     private static final int VIBRATE_HINT_DURATION = 50;
-    private static final AudioAttributes SONFICIATION_VIBRATION_ATTRIBUTES =
+    private static final AudioAttributes SONIFICIATION_VIBRATION_ATTRIBUTES =
             new AudioAttributes.Builder()
                     .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                     .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
@@ -100,6 +106,7 @@
     private final W mWorker;
     private final Context mContext;
     private AudioManager mAudio;
+    private IAudioService mAudioService;
     protected StatusBar mStatusBar;
     private final NotificationManager mNoMan;
     private final SettingObserver mObserver;
@@ -113,6 +120,7 @@
     private boolean mShowA11yStream;
     private boolean mShowVolumeDialog;
     private boolean mShowSafetyWarning;
+    private long mLastToggledRingerOn;
     private final NotificationManager mNotificationManager;
 
     private boolean mDestroyed;
@@ -140,6 +148,8 @@
         mReceiver.init();
         mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
         mHasVibrator = mVibrator != null && mVibrator.hasVibrator();
+        mAudioService = IAudioService.Stub.asInterface(
+                ServiceManager.getService(Context.AUDIO_SERVICE));
         updateStatusBar();
 
         boolean accessibilityVolumeStreamActive = context.getSystemService(
@@ -300,10 +310,24 @@
       mShowSafetyWarning = safetyWarning;
     }
 
-    public void vibrate() {
+    @Override
+    public void scheduleTouchFeedback() {
+        mLastToggledRingerOn = System.currentTimeMillis();
+    }
+
+    private void playTouchFeedback() {
+        if (System.currentTimeMillis() - mLastToggledRingerOn < TOUCH_FEEDBACK_TIMEOUT_MS) {
+            try {
+                mAudioService.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD);
+            } catch (RemoteException e) {
+                // ignore
+            }
+        }
+    }
+
+    public void vibrate(VibrationEffect effect) {
         if (mHasVibrator) {
-            mVibrator.vibrate(VibrationEffect.createOneShot(VIBRATE_HINT_DURATION,
-                    VibrationEffect.DEFAULT_AMPLITUDE), SONFICIATION_VIBRATION_ATTRIBUTES);
+            mVibrator.vibrate(effect, SONIFICIATION_VIBRATION_ATTRIBUTES);
         }
     }
 
@@ -425,7 +449,7 @@
         for (int stream : STREAMS.keySet()) {
             updateStreamLevelW(stream, getAudioManagerStreamVolume(stream));
             streamStateW(stream).levelMin = getAudioManagerStreamMinVolume(stream);
-            streamStateW(stream).levelMax = getAudioManagerStreamMaxVolume(stream);
+            streamStateW(stream).levelMax = Math.max(1, getAudioManagerStreamMaxVolume(stream));
             updateStreamMuteW(stream, mAudio.isStreamMute(stream));
             final StreamState ss = streamStateW(stream);
             ss.muteSupported = mAudio.isStreamAffectedByMute(stream);
@@ -556,6 +580,11 @@
         if (rm == mState.ringerModeInternal) return false;
         mState.ringerModeInternal = rm;
         Events.writeEvent(mContext, Events.EVENT_INTERNAL_RINGER_MODE_CHANGED, rm);
+
+        if (mState.ringerModeInternal == RINGER_MODE_NORMAL) {
+            playTouchFeedback();
+        }
+
         return true;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 71c7f80..acdd0c7 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -22,6 +22,10 @@
 import static android.media.AudioManager.RINGER_MODE_SILENT;
 import static android.media.AudioManager.RINGER_MODE_VIBRATE;
 import static android.media.AudioManager.STREAM_ACCESSIBILITY;
+import static android.media.AudioManager.STREAM_ALARM;
+import static android.media.AudioManager.STREAM_MUSIC;
+import static android.media.AudioManager.STREAM_RING;
+import static android.media.AudioManager.STREAM_VOICE_CALL;
 import static android.view.View.GONE;
 import static android.view.View.VISIBLE;
 
@@ -41,13 +45,17 @@
 import android.graphics.Color;
 import android.graphics.PixelFormat;
 import android.graphics.drawable.ColorDrawable;
+import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.AudioSystem;
+import android.media.MediaPlayer;
 import android.os.Debug;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.SystemClock;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.text.InputFilter;
@@ -126,6 +134,7 @@
     private final Accessibility mAccessibility = new Accessibility();
     private final ColorStateList mActiveSliderTint;
     private final ColorStateList mInactiveSliderTint;
+    private final Vibrator mVibrator;
 
     private boolean mShowing;
     private boolean mShowA11yStream;
@@ -146,6 +155,7 @@
         mActiveSliderTint = ColorStateList.valueOf(Utils.getColorAccent(mContext));
         mInactiveSliderTint = loadColorStateList(R.color.volume_slider_inactive);
         mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
+        mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
     }
 
     public void init(int windowType, Callback callback) {
@@ -203,6 +213,9 @@
                     .setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator())
                     .withEndAction(() -> {
                         mWindow.getDecorView().requestAccessibilityFocus();
+                        if (!Prefs.getBoolean(mContext, Prefs.Key.TOUCHED_RINGER_TOGGLE, true)) {
+                            mRingerIcon.postOnAnimationDelayed(mSinglePress, 1500);
+                        }
                     })
                     .start();
         });
@@ -223,12 +236,16 @@
         mSettingsIcon = mDialog.findViewById(R.id.settings);
 
         if (mRows.isEmpty()) {
+            if (!AudioSystem.isSingleVolume(mContext)) {
+                addRow(STREAM_ACCESSIBILITY, R.drawable.ic_volume_accessibility,
+                        R.drawable.ic_volume_accessibility, true, false);
+            }
             addRow(AudioManager.STREAM_MUSIC,
                     R.drawable.ic_volume_media, R.drawable.ic_volume_media_mute, true, true);
             if (!AudioSystem.isSingleVolume(mContext)) {
                 addRow(AudioManager.STREAM_RING,
                         R.drawable.ic_volume_ringer, R.drawable.ic_volume_ringer_mute, true, false);
-                addRow(AudioManager.STREAM_ALARM,
+                addRow(STREAM_ALARM,
                         R.drawable.ic_volume_alarm, R.drawable.ic_volume_alarm_mute, true, false);
                 addRow(AudioManager.STREAM_VOICE_CALL,
                         R.drawable.ic_volume_voice, R.drawable.ic_volume_voice, false, false);
@@ -236,8 +253,6 @@
                         R.drawable.ic_volume_bt_sco, R.drawable.ic_volume_bt_sco, false, false);
                 addRow(AudioManager.STREAM_SYSTEM, R.drawable.ic_volume_system,
                         R.drawable.ic_volume_system_mute, false, false);
-                addRow(STREAM_ACCESSIBILITY, R.drawable.ic_volume_accessibility,
-                        R.drawable.ic_volume_accessibility, true, false);
             }
         } else {
             addExistingRows();
@@ -287,11 +302,11 @@
         if (D.BUG) Slog.d(TAG, "Adding row for stream " + stream);
         VolumeRow row = new VolumeRow();
         initRow(row, stream, iconRes, iconMuteRes, important, defaultStream);
-        int rowSize;
-        if (mShowA11yStream && dynamic && (rowSize = mRows.size()) > 1) {
-            // A11y Stream should be the first in the list, so it's shown to start of other rows
-            mDialogRowsView.addView(row.view, 0);
-            mRows.add(rowSize - 2, row);
+        if (dynamic && mRows.size() > 2) {
+            // Dynamic Streams should be the first in the list, so they're shown to start of
+            // everything except a11y
+            mDialogRowsView.addView(row.view, 1);
+            mRows.add(1, row);
         } else {
             mDialogRowsView.addView(row.view);
             mRows.add(row);
@@ -315,6 +330,11 @@
                 return row;
             }
         }
+        for (VolumeRow row : mRows) {
+            if (row.stream == STREAM_MUSIC) {
+                return row;
+            }
+        }
         return mRows.get(0);
     }
 
@@ -414,6 +434,7 @@
         mRingerIcon.setOnClickListener(v -> {
             Events.writeEvent(mContext, Events.EVENT_ICON_CLICK, AudioManager.STREAM_RING,
                     mRingerIcon.getTag());
+            Prefs.putBoolean(mContext, Prefs.Key.TOUCHED_RINGER_TOGGLE, true);
             final StreamState ss = mState.states.get(AudioManager.STREAM_RING);
             if (ss == null) {
                 return;
@@ -424,7 +445,6 @@
             final boolean hasVibrator = mController.hasVibrator();
             if (mState.ringerModeInternal == AudioManager.RINGER_MODE_NORMAL) {
                 if (hasVibrator) {
-                    mController.vibrate();
                     newRingerMode = AudioManager.RINGER_MODE_VIBRATE;
                 } else {
                     newRingerMode = AudioManager.RINGER_MODE_SILENT;
@@ -438,30 +458,56 @@
                 }
             }
             updateRingerH();
-
+            provideTouchFeedbackH(newRingerMode);
             mController.setRingerMode(newRingerMode, false);
             maybeShowToastH(newRingerMode);
         });
         updateRingerH();
     }
 
+
+    private void provideTouchFeedbackH(int newRingerMode) {
+        VibrationEffect effect = null;
+        switch (newRingerMode) {
+            case RINGER_MODE_NORMAL:
+                mController.scheduleTouchFeedback();
+                break;
+            case RINGER_MODE_SILENT:
+                effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
+                break;
+            case RINGER_MODE_VIBRATE:
+            default:
+                effect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
+        }
+        if (effect != null) {
+            mController.vibrate(effect);
+        }
+    }
+
     private void maybeShowToastH(int newRingerMode) {
         int seenToastCount = Prefs.getInt(mContext, Prefs.Key.SEEN_RINGER_GUIDANCE_COUNT, 0);
 
         if (seenToastCount > VolumePrefs.SHOW_RINGER_TOAST_COUNT) {
             return;
         }
-        int toastText;
+        CharSequence toastText = null;
         switch (newRingerMode) {
             case RINGER_MODE_NORMAL:
-                toastText = R.string.volume_dialog_ringer_guidance_ring;
+                final StreamState ss = mState.states.get(AudioManager.STREAM_RING);
+                if (ss != null) {
+                    toastText = mContext.getString(
+                            R.string.volume_dialog_ringer_guidance_ring,
+                            Utils.formatPercentage(ss.level, ss.levelMax));
+                }
                 break;
             case RINGER_MODE_SILENT:
-                toastText = com.android.internal.R.string.volume_dialog_ringer_guidance_silent;
+                toastText = mContext.getString(
+                        com.android.internal.R.string.volume_dialog_ringer_guidance_silent);
                 break;
             case RINGER_MODE_VIBRATE:
             default:
-                toastText = com.android.internal.R.string.volume_dialog_ringer_guidance_vibrate;
+                toastText = mContext.getString(
+                        com.android.internal.R.string.volume_dialog_ringer_guidance_vibrate);
         }
 
         Toast.makeText(mContext, toastText, Toast.LENGTH_SHORT).show();
@@ -538,7 +584,7 @@
     }
 
     private boolean shouldBeVisibleH(VolumeRow row, VolumeRow activeRow) {
-        boolean isActive = row == activeRow;
+        boolean isActive = row.stream == activeRow.stream;
         if (row.stream == AudioSystem.STREAM_ACCESSIBILITY) {
             return mShowA11yStream;
         }
@@ -550,7 +596,17 @@
             return true;
         }
 
-        return row.defaultStream || isActive;
+        if (isActive) {
+            return true;
+        }
+
+        if (row.defaultStream) {
+            return activeRow.stream == STREAM_RING
+                    || activeRow.stream == STREAM_ALARM
+                    || activeRow.stream == STREAM_VOICE_CALL;
+        }
+
+        return false;
     }
 
     private void updateRowsH(final VolumeRow activeRow) {
@@ -670,7 +726,8 @@
         if (mActiveStream != state.activeStream) {
             mPrevActiveStream = mActiveStream;
             mActiveStream = state.activeStream;
-            updateRowsH(getActiveRow());
+            VolumeRow activeRow = getActiveRow();
+            updateRowsH(activeRow);
             rescheduleTimeoutH();
         }
         for (VolumeRow row : mRows) {
@@ -696,7 +753,7 @@
         final boolean isA11yStream = row.stream == STREAM_ACCESSIBILITY;
         final boolean isRingStream = row.stream == AudioManager.STREAM_RING;
         final boolean isSystemStream = row.stream == AudioManager.STREAM_SYSTEM;
-        final boolean isAlarmStream = row.stream == AudioManager.STREAM_ALARM;
+        final boolean isAlarmStream = row.stream == STREAM_ALARM;
         final boolean isMusicStream = row.stream == AudioManager.STREAM_MUSIC;
         final boolean isRingVibrate = isRingStream
                 && mState.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE;
@@ -921,6 +978,21 @@
         }
     }
 
+    private Runnable mSinglePress = new Runnable() {
+        @Override
+        public void run() {
+            mRingerIcon.setPressed(true);
+            mRingerIcon.postOnAnimationDelayed(mSingleUnpress, 200);
+        }
+    };
+
+    private Runnable mSingleUnpress = new Runnable() {
+        @Override
+        public void run() {
+            mRingerIcon.setPressed(false);
+        }
+    };
+
     private final VolumeDialogController.Callbacks mControllerCallbackH
             = new VolumeDialogController.Callbacks() {
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java
index 173400f..434327c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java
@@ -43,7 +43,7 @@
     public static final String PREF_ADJUST_ALARMS = "pref_adjust_alarms";
     public static final String PREF_ADJUST_NOTIFICATION = "pref_adjust_notification";
 
-    public static final int SHOW_RINGER_TOAST_COUNT = 9;
+    public static final int SHOW_RINGER_TOAST_COUNT = 12;
 
     public static final boolean DEFAULT_SHOW_HEADERS = true;
     public static final boolean DEFAULT_ENABLE_AUTOMUTE = true;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 4a66bb7..b31a2dc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -41,6 +41,7 @@
 import android.app.StatusBarManager;
 import android.app.trust.TrustManager;
 import android.content.Context;
+import android.content.pm.UserInfo;
 import android.hardware.fingerprint.FingerprintManager;
 import android.metrics.LogMaker;
 import android.os.Binder;
@@ -71,6 +72,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.statusbar.ActivatableNotificationView;
@@ -91,6 +93,7 @@
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
@@ -98,6 +101,7 @@
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 import org.junit.Before;
@@ -134,6 +138,7 @@
     @Mock private VisualStabilityManager mVisualStabilityManager;
     @Mock private NotificationListener mNotificationListener;
     @Mock private KeyguardViewMediator mKeyguardViewMediator;
+    @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
 
     private TestableStatusBar mStatusBar;
     private FakeMetricsLogger mMetricsLogger;
@@ -146,9 +151,7 @@
         MockitoAnnotations.initMocks(this);
         mDependency.injectMockDependency(AssistManager.class);
         mDependency.injectMockDependency(DeviceProvisionedController.class);
-        mDependency.injectMockDependency(NotificationGroupManager.class);
         mDependency.injectMockDependency(NotificationGutsManager.class);
-        mDependency.injectMockDependency(NotificationRemoteInputManager.class);
         mDependency.injectMockDependency(NotificationMediaManager.class);
         mDependency.injectMockDependency(ForegroundServiceController.class);
         mDependency.injectTestDependency(NotificationViewHierarchyManager.class,
@@ -202,7 +205,12 @@
                 mPowerManager, mNotificationPanelView, mBarService, mNotificationListener,
                 mNotificationLogger, mVisualStabilityManager, mViewHierarchyManager,
                 mEntryManager, mScrimController, mFingerprintUnlockController,
-                mock(ActivityLaunchAnimator.class), mKeyguardViewMediator);
+                mock(ActivityLaunchAnimator.class), mKeyguardViewMediator,
+                mock(NotificationRemoteInputManager.class), mock(NotificationGroupManager.class),
+                mock(FalsingManager.class), mock(StatusBarWindowManager.class),
+                mock(NotificationIconAreaController.class), mock(DozeScrimController.class),
+                mock(NotificationShelf.class), mLockscreenUserManager,
+                mock(CommandQueue.class));
         mStatusBar.mContext = mContext;
         mStatusBar.mComponents = mContext.getComponents();
         mEntryManager.setUpForTest(mStatusBar, mStackScroller, mStatusBar, mHeadsUpManager,
@@ -529,11 +537,7 @@
     @Test
     @RunWithLooper(setAsMainLooper = true)
     public void testUpdateKeyguardState_DoesNotCrash() {
-        mStatusBar.mStatusBarWindow = mock(StatusBarWindowView.class);
         mStatusBar.mState = StatusBarState.KEYGUARD;
-        mStatusBar.mDozeScrimController = mock(DozeScrimController.class);
-        mStatusBar.mNotificationIconAreaController = mock(NotificationIconAreaController.class);
-        mStatusBar.mLockscreenUserManager = mock(NotificationLockscreenUserManager.class);
         when(mStatusBar.mLockscreenUserManager.getCurrentProfiles()).thenReturn(
                 new SparseArray<>());
         mStatusBar.updateKeyguardState(false, false);
@@ -541,9 +545,6 @@
 
     @Test
     public void testFingerprintNotification_UpdatesScrims() {
-        mStatusBar.mStatusBarWindowManager = mock(StatusBarWindowManager.class);
-        mStatusBar.mDozeScrimController = mock(DozeScrimController.class);
-        mStatusBar.mNotificationIconAreaController = mock(NotificationIconAreaController.class);
         mStatusBar.notifyFpAuthModeChanged();
         verify(mScrimController).transitionTo(any(), any());
     }
@@ -629,6 +630,32 @@
         verify(mStackScroller).changeViewPosition(any(FooterView.class), eq(-1 /* end */));
     }
 
+    @Test
+    public void testSetState_changesIsFullScreenUserSwitcherState() {
+        mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
+        assertFalse(mStatusBar.isFullScreenUserSwitcherState());
+
+        mStatusBar.setBarStateForTest(StatusBarState.FULLSCREEN_USER_SWITCHER);
+        assertTrue(mStatusBar.isFullScreenUserSwitcherState());
+    }
+
+    @Test
+    public void testShowKeyguardImplementation_setsState() {
+        when(mLockscreenUserManager.getCurrentProfiles()).thenReturn(new SparseArray<>());
+
+        mStatusBar.setBarStateForTest(StatusBarState.SHADE);
+
+        // By default, showKeyguardImpl sets state to KEYGUARD.
+        mStatusBar.showKeyguardImpl();
+        assertTrue(mStatusBar.mState == StatusBarState.KEYGUARD);
+
+        // If useFullscreenUserSwitcher is true, state is set to FULLSCREEN_USER_SWITCHER.
+        mStatusBar.mUserSwitcherController = mock(UserSwitcherController.class);
+        when(mStatusBar.mUserSwitcherController.useFullscreenUserSwitcher()).thenReturn(true);
+        mStatusBar.showKeyguardImpl();
+        assertTrue(mStatusBar.mState == StatusBarState.FULLSCREEN_USER_SWITCHER);
+    }
+
     static class TestableStatusBar extends StatusBar {
         public TestableStatusBar(StatusBarKeyguardViewManager man,
                 UnlockMethodCache unlock, KeyguardIndicationController key,
@@ -640,7 +667,16 @@
                 NotificationViewHierarchyManager viewHierarchyManager,
                 TestableNotificationEntryManager entryManager, ScrimController scrimController,
                 FingerprintUnlockController fingerprintUnlockController,
-                ActivityLaunchAnimator launchAnimator, KeyguardViewMediator keyguardViewMediator) {
+                ActivityLaunchAnimator launchAnimator, KeyguardViewMediator keyguardViewMediator,
+                NotificationRemoteInputManager notificationRemoteInputManager,
+                NotificationGroupManager notificationGroupManager,
+                FalsingManager falsingManager,
+                StatusBarWindowManager statusBarWindowManager,
+                NotificationIconAreaController notificationIconAreaController,
+                DozeScrimController dozeScrimController,
+                NotificationShelf notificationShelf,
+                NotificationLockscreenUserManager notificationLockscreenUserManager,
+                CommandQueue commandQueue) {
             mStatusBarKeyguardViewManager = man;
             mUnlockMethodCache = unlock;
             mKeyguardIndicationController = key;
@@ -660,6 +696,15 @@
             mActivityLaunchAnimator = launchAnimator;
             mKeyguardViewMediator = keyguardViewMediator;
             mClearAllEnabled = true;
+            mRemoteInputManager = notificationRemoteInputManager;
+            mGroupManager = notificationGroupManager;
+            mFalsingManager = falsingManager;
+            mStatusBarWindowManager = statusBarWindowManager;
+            mNotificationIconAreaController = notificationIconAreaController;
+            mDozeScrimController = dozeScrimController;
+            mNotificationShelf = notificationShelf;
+            mLockscreenUserManager = notificationLockscreenUserManager;
+            mCommandQueue = commandQueue;
         }
 
         private WakefulnessLifecycle createAwakeWakefulnessLifecycle() {
diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-land/config.xml b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-land/config.xml
deleted file mode 100644
index 1aa1af3..0000000
--- a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-land/config.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<!--
-  ~ Copyright (C) 2018 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-
-<resources>
-    <dimen name="quick_qs_offset_height">@dimen/status_bar_height_landscape</dimen>
-    <!-- Total height of QQS in landscape, this is effectively status_bar_height_landscape + 128 -->
-    <dimen name="quick_qs_total_height">156dp</dimen>
-</resources>
\ No newline at end of file
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-land/config.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-land/config.xml
deleted file mode 100644
index 1aa1af3..0000000
--- a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-land/config.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<!--
-  ~ Copyright (C) 2018 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-
-<resources>
-    <dimen name="quick_qs_offset_height">@dimen/status_bar_height_landscape</dimen>
-    <!-- Total height of QQS in landscape, this is effectively status_bar_height_landscape + 128 -->
-    <dimen name="quick_qs_total_height">156dp</dimen>
-</resources>
\ No newline at end of file
diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-land/config.xml b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-land/config.xml
deleted file mode 100644
index 1aa1af3..0000000
--- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-land/config.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<!--
-  ~ Copyright (C) 2018 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-
-<resources>
-    <dimen name="quick_qs_offset_height">@dimen/status_bar_height_landscape</dimen>
-    <!-- Total height of QQS in landscape, this is effectively status_bar_height_landscape + 128 -->
-    <dimen name="quick_qs_total_height">156dp</dimen>
-</resources>
\ No newline at end of file
diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-land/config.xml b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-land/config.xml
deleted file mode 100644
index 1aa1af3..0000000
--- a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-land/config.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<!--
-  ~ Copyright (C) 2018 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-
-<resources>
-    <dimen name="quick_qs_offset_height">@dimen/status_bar_height_landscape</dimen>
-    <!-- Total height of QQS in landscape, this is effectively status_bar_height_landscape + 128 -->
-    <dimen name="quick_qs_total_height">156dp</dimen>
-</resources>
\ No newline at end of file
diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-land/config.xml b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-land/config.xml
deleted file mode 100644
index 1aa1af3..0000000
--- a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-land/config.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<!--
-  ~ Copyright (C) 2018 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-
-<resources>
-    <dimen name="quick_qs_offset_height">@dimen/status_bar_height_landscape</dimen>
-    <!-- Total height of QQS in landscape, this is effectively status_bar_height_landscape + 128 -->
-    <dimen name="quick_qs_total_height">156dp</dimen>
-</resources>
\ No newline at end of file
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 9c74188..1605252 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -249,12 +249,12 @@
   optional int32 num_wificond_crashes = 54;
 
   // Indicates the number of times an error was encountered in
-  // Wifi HAL when wifi was turned on.
-  optional int32 num_wifi_on_failure_due_to_hal = 55;
+  // Wifi HAL on |WifiNative.setupInterfaceForClientMode|.
+  optional int32 num_setup_client_interface_failure_due_to_hal = 55;
 
   // Indicates the number of times an error was encountered in
-  // Wificond when wifi was turned on.
-  optional int32 num_wifi_on_failure_due_to_wificond = 56;
+  // Wificond on |WifiNative.setupInterfaceForClientMode|.
+  optional int32 num_setup_client_interface_failure_due_to_wificond = 56;
 
   // Wi-Fi Aware metrics
   optional WifiAwareLog wifi_aware_log = 57;
@@ -385,6 +385,34 @@
 
   // Histogram counting instances of scans with N many 802.11mc (RTT) supporting APs
   repeated NumConnectableNetworksBucket observed_80211mc_supporting_aps_in_scan_histogram = 95;
+
+  // Total number of times supplicant crashed.
+  optional int32 num_supplicant_crashes = 96;
+
+  // Total number of times hostapd crashed.
+  optional int32 num_hostapd_crashes = 97;
+
+  // Indicates the number of times an error was encountered in
+  // supplicant on |WifiNative.setupInterfaceForClientMode|.
+  optional int32 num_setup_client_interface_failure_due_to_supplicant = 98;
+
+  // Indicates the number of times an error was encountered in
+  // Wifi HAL on |WifiNative.setupInterfaceForSoftApMode|.
+  optional int32 num_setup_soft_ap_interface_failure_due_to_hal = 99;
+
+  // Indicates the number of times an error was encountered in
+  // Wifi HAL on |WifiNative.setupInterfaceForSoftApMode|.
+  optional int32 num_setup_soft_ap_interface_failure_due_to_wificond = 100;
+
+  // Indicates the number of times an error was encountered in
+  // Wifi HAL on |WifiNative.setupInterfaceForSoftApMode|.
+  optional int32 num_setup_soft_ap_interface_failure_due_to_hostapd = 101;
+
+  // Indicates the number of times we got an interface down in client mode.
+  optional int32 num_client_interface_down = 102;
+
+  // Indicates the number of times we got an interface down in softap mode.
+  optional int32 num_soft_ap_interface_down = 103;
 }
 
 // Information that gets logged for every WiFi connection.
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 706a6ab..e14584f 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2503,8 +2503,8 @@
 
         pw.print(prefix); pw.print("mHasCallback: "); pw.println(mHasCallback);
         if (mClientState != null) {
-            pw.print(prefix); pw.println("mClientState: "); pw.print(mClientState.getSize()); pw
-                .println(" items");
+            pw.print(prefix); pw.print("mClientState: "); pw.print(mClientState.getSize()); pw
+                .println(" bytes");
         }
         pw.print(prefix); pw.print("mCompatMode: "); pw.println(mCompatMode);
         pw.print(prefix); pw.print("mUrlBar: ");
diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java
index 106b37f..bef650b 100644
--- a/services/core/java/com/android/server/am/LockTaskController.java
+++ b/services/core/java/com/android/server/am/LockTaskController.java
@@ -285,6 +285,16 @@
         return false;
     }
 
+    /**
+     * @return the root task of the lock task.
+     */
+    TaskRecord getRootTask() {
+        if (mLockTaskModeTasks.isEmpty()) {
+            return null;
+        }
+        return mLockTaskModeTasks.get(0);
+    }
+
     private boolean isLockTaskModeViolationInternal(TaskRecord task, boolean isNewClearTask) {
         // TODO: Double check what's going on here. If the task is already in lock task mode, it's
         // likely whitelisted, so will return false below.
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index fcf00ce..1d305fb 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -1155,6 +1155,11 @@
                 }
         }
 
+        // If we're in lock task mode, ignore the root task
+        if (task == mService.mLockTaskController.getRootTask()) {
+            return false;
+        }
+
         return true;
     }
 
diff --git a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
index 32b1d1a..7a6d964 100644
--- a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
+++ b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
@@ -17,6 +17,7 @@
 package com.android.server.broadcastradio.hal1;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.hardware.radio.ITuner;
 import android.hardware.radio.ITunerCallback;
 import android.hardware.radio.ProgramList;
@@ -87,8 +88,9 @@
         mTuner.close();
     }
 
-    void startProgramListUpdates(@NonNull ProgramList.Filter filter) {
-        mProgramListFilter.set(Objects.requireNonNull(filter));
+    void startProgramListUpdates(@Nullable ProgramList.Filter filter) {
+        if (filter == null) filter = new ProgramList.Filter();
+        mProgramListFilter.set(filter);
         sendProgramListUpdate();
     }
 
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
index 248151c..9730c9a 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
@@ -375,7 +375,9 @@
         );
     }
 
-    static @NonNull ProgramFilter programFilterToHal(@NonNull ProgramList.Filter filter) {
+    static @NonNull ProgramFilter programFilterToHal(@Nullable ProgramList.Filter filter) {
+        if (filter == null) filter = new ProgramList.Filter();
+
         ProgramFilter hwFilter = new ProgramFilter();
 
         filter.getIdentifierTypes().stream().forEachOrdered(hwFilter.identifierTypes::add);
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index eee830f..1bc7423 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -56,6 +56,7 @@
 import android.net.NetworkState;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
+import android.net.util.InterfaceSet;
 import android.net.util.PrefixUtils;
 import android.net.util.SharedLog;
 import android.net.util.VersionedBroadcastListener;
@@ -98,6 +99,7 @@
 import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
 import com.android.server.connectivity.tethering.TetheringConfiguration;
 import com.android.server.connectivity.tethering.TetheringDependencies;
+import com.android.server.connectivity.tethering.TetheringInterfaceUtils;
 import com.android.server.connectivity.tethering.UpstreamNetworkMonitor;
 import com.android.server.net.BaseNetworkObserver;
 
@@ -181,9 +183,10 @@
     private final VersionedBroadcastListener mCarrierConfigChange;
     // TODO: Delete SimChangeListener; it's obsolete.
     private final SimChangeListener mSimChange;
+    private final TetheringDependencies mDeps;
 
     private volatile TetheringConfiguration mConfig;
-    private String mCurrentUpstreamIface;
+    private InterfaceSet mCurrentUpstreamIfaceSet;
     private Notification.Builder mTetheredNotificationBuilder;
     private int mLastNotificationId;
 
@@ -202,12 +205,13 @@
         mPolicyManager = policyManager;
         mLooper = looper;
         mSystemProperties = systemProperties;
+        mDeps = deps;
 
         mPublicSync = new Object();
 
         mTetherStates = new ArrayMap<>();
 
-        mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper);
+        mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper, deps);
         mTetherMasterSM.start();
 
         final Handler smHandler = mTetherMasterSM.getHandler();
@@ -215,8 +219,8 @@
                 deps.getOffloadHardwareInterface(smHandler, mLog),
                 mContext.getContentResolver(), mNMService,
                 mLog);
-        mUpstreamNetworkMonitor = new UpstreamNetworkMonitor(
-                mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
+        mUpstreamNetworkMonitor = deps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog,
+                TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
         mForwardedDownstreams = new HashSet<>();
 
         IntentFilter filter = new IntentFilter();
@@ -1160,12 +1164,11 @@
     }
 
     // Needed because the canonical source of upstream truth is just the
-    // upstream interface name, |mCurrentUpstreamIface|.  This is ripe for
-    // future simplification, once the upstream Network is canonical.
+    // upstream interface set, |mCurrentUpstreamIfaceSet|.
     private boolean pertainsToCurrentUpstream(NetworkState ns) {
-        if (ns != null && ns.linkProperties != null && mCurrentUpstreamIface != null) {
+        if (ns != null && ns.linkProperties != null && mCurrentUpstreamIfaceSet != null) {
             for (String ifname : ns.linkProperties.getAllInterfaceNames()) {
-                if (mCurrentUpstreamIface.equals(ifname)) {
+                if (mCurrentUpstreamIfaceSet.ifnames.contains(ifname)) {
                     return true;
                 }
             }
@@ -1241,7 +1244,7 @@
 
         private static final int UPSTREAM_SETTLE_TIME_MS     = 10000;
 
-        TetherMasterSM(String name, Looper looper) {
+        TetherMasterSM(String name, Looper looper, TetheringDependencies deps) {
             super(name, looper);
 
             mInitialState = new InitialState();
@@ -1261,7 +1264,7 @@
             addState(mSetDnsForwardersErrorState);
 
             mNotifyList = new ArrayList<>();
-            mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList, mLog);
+            mIPv6TetheringCoordinator = deps.getIPv6TetheringCoordinator(mNotifyList, mLog);
             mOffload = new OffloadWrapper();
 
             setInitialState(mInitialState);
@@ -1360,31 +1363,27 @@
         }
 
         protected void setUpstreamNetwork(NetworkState ns) {
-            String iface = null;
+            InterfaceSet ifaces = null;
             if (ns != null) {
                 // Find the interface with the default IPv4 route. It may be the
                 // interface described by linkProperties, or one of the interfaces
                 // stacked on top of it.
                 mLog.i("Looking for default routes on: " + ns.linkProperties);
-                final String iface4 = getIPv4DefaultRouteInterface(ns);
-                final String iface6 = getIPv6DefaultRouteInterface(ns);
-                mLog.i("IPv4/IPv6 upstream interface(s): " + iface4 + "/" + iface6);
-
-                iface = (iface4 != null) ? iface4 : null /* TODO: iface6 */;
+                ifaces = TetheringInterfaceUtils.getTetheringInterfaces(ns);
+                mLog.i("Found upstream interface(s): " + ifaces);
             }
 
-            if (iface != null) {
+            if (ifaces != null) {
                 setDnsForwarders(ns.network, ns.linkProperties);
             }
-            notifyDownstreamsOfNewUpstreamIface(iface);
+            notifyDownstreamsOfNewUpstreamIface(ifaces);
             if (ns != null && pertainsToCurrentUpstream(ns)) {
                 // If we already have NetworkState for this network examine
                 // it immediately, because there likely will be no second
                 // EVENT_ON_AVAILABLE (it was already received).
                 handleNewUpstreamNetworkState(ns);
-            } else if (mCurrentUpstreamIface == null) {
-                // There are no available upstream networks, or none that
-                // have an IPv4 default route (current metric for success).
+            } else if (mCurrentUpstreamIfaceSet == null) {
+                // There are no available upstream networks.
                 handleNewUpstreamNetworkState(null);
             }
         }
@@ -1411,12 +1410,10 @@
             }
         }
 
-        protected void notifyDownstreamsOfNewUpstreamIface(String ifaceName) {
-            mLog.log("Notifying downstreams of upstream=" + ifaceName);
-            mCurrentUpstreamIface = ifaceName;
+        protected void notifyDownstreamsOfNewUpstreamIface(InterfaceSet ifaces) {
+            mCurrentUpstreamIfaceSet = ifaces;
             for (TetherInterfaceStateMachine sm : mNotifyList) {
-                sm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
-                        ifaceName);
+                sm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED, ifaces);
             }
         }
 
@@ -1488,7 +1485,7 @@
                 // For example, after CONNECTIVITY_ACTION listening is removed, here
                 // is where we could observe a Wi-Fi network becoming available and
                 // passing validation.
-                if (mCurrentUpstreamIface == null) {
+                if (mCurrentUpstreamIfaceSet == null) {
                     // If we have no upstream interface, try to run through upstream
                     // selection again.  If, for example, IPv4 connectivity has shown up
                     // after IPv6 (e.g., 464xlat became available) we want the chance to
@@ -1512,8 +1509,7 @@
                     handleNewUpstreamNetworkState(ns);
                     break;
                 case UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES:
-                    setDnsForwarders(ns.network, ns.linkProperties);
-                    handleNewUpstreamNetworkState(ns);
+                    chooseUpstreamType(false);
                     break;
                 case UpstreamNetworkMonitor.EVENT_ON_LOST:
                     // TODO: Re-evaluate possible upstreams. Currently upstream
@@ -1586,7 +1582,7 @@
                         if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
                         handleInterfaceServingStateActive(message.arg1, who);
                         who.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
-                                mCurrentUpstreamIface);
+                                mCurrentUpstreamIfaceSet);
                         // If there has been a change and an upstream is now
                         // desired, kick off the selection process.
                         final boolean previousUpstreamWanted = updateUpstreamWanted();
@@ -1864,7 +1860,7 @@
                 pw.println(" - lastError = " + tetherState.lastError);
             }
             pw.println("Upstream wanted: " + upstreamWanted());
-            pw.println("Current upstream interface: " + mCurrentUpstreamIface);
+            pw.println("Current upstream interface(s): " + mCurrentUpstreamIfaceSet);
             pw.decreaseIndent();
         }
 
@@ -1997,7 +1993,7 @@
         final TetherState tetherState = new TetherState(
                 new TetherInterfaceStateMachine(
                     iface, mLooper, interfaceType, mLog, mNMService, mStatsService,
-                    makeControlCallback(iface)));
+                    makeControlCallback(iface), mDeps));
         mTetherStates.put(iface, tetherState);
         tetherState.stateMachine.start();
     }
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index c9bdcf1..2fda08e 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -151,6 +151,13 @@
                 .multiply(BigInteger.valueOf(howManyPercentIsMost))
                 .divide(BigInteger.valueOf(100));
     }
+    // How many routes to evaluate before bailing and declaring this Vpn should provide
+    // the INTERNET capability. This is necessary because computing the adress space is
+    // O(n²) and this is running in the system service, so a limit is needed to alleviate
+    // the risk of attack.
+    // This is taken as a total of IPv4 + IPV6 routes for simplicity, but the algorithm
+    // is actually O(n²)+O(n²).
+    private static final int MAX_ROUTES_TO_EVALUATE = 150;
 
     // TODO: create separate trackers for each unique VPN to support
     // automated reconnection
@@ -862,10 +869,12 @@
      */
     @VisibleForTesting
     static boolean providesRoutesToMostDestinations(LinkProperties lp) {
+        final List<RouteInfo> routes = lp.getAllRoutes();
+        if (routes.size() > MAX_ROUTES_TO_EVALUATE) return true;
         final Comparator<IpPrefix> prefixLengthComparator = IpPrefix.lengthComparator();
         TreeSet<IpPrefix> ipv4Prefixes = new TreeSet<>(prefixLengthComparator);
         TreeSet<IpPrefix> ipv6Prefixes = new TreeSet<>(prefixLengthComparator);
-        for (final RouteInfo route : lp.getAllRoutes()) {
+        for (final RouteInfo route : routes) {
             IpPrefix destination = route.getDestination();
             if (destination.isIPv4()) {
                 ipv4Prefixes.add(destination);
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
index 518f6c1..ba67c94 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
@@ -30,10 +30,8 @@
 
 import java.net.Inet6Address;
 import java.net.InetAddress;
-import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.Random;
 
@@ -119,7 +117,7 @@
         if (VDBG) {
             Log.d(TAG, "updateUpstreamNetworkState: " + toDebugString(ns));
         }
-        if (!canTetherIPv6(ns, mLog)) {
+        if (TetheringInterfaceUtils.getIPv6Interface(ns) == null) {
             stopIPv6TetheringOnAllInterfaces();
             setUpstreamNetworkState(null);
             return;
@@ -208,70 +206,6 @@
         return null;
     }
 
-    private static boolean canTetherIPv6(NetworkState ns, SharedLog sharedLog) {
-        // Broadly speaking:
-        //
-        //     [1] does the upstream have an IPv6 default route?
-        //
-        // and
-        //
-        //     [2] does the upstream have one or more global IPv6 /64s
-        //         dedicated to this device?
-        //
-        // In lieu of Prefix Delegation and other evaluation of whether a
-        // prefix may or may not be dedicated to this device, for now just
-        // check whether the upstream is TRANSPORT_CELLULAR. This works
-        // because "[t]he 3GPP network allocates each default bearer a unique
-        // /64 prefix", per RFC 6459, Section 5.2.
-
-        final boolean canTether =
-                (ns != null) && (ns.network != null) &&
-                (ns.linkProperties != null) && (ns.networkCapabilities != null) &&
-                // At least one upstream DNS server:
-                ns.linkProperties.isProvisioned() &&
-                // Minimal amount of IPv6 provisioning:
-                ns.linkProperties.hasIPv6DefaultRoute() &&
-                ns.linkProperties.hasGlobalIPv6Address() &&
-                // Temporary approximation of "dedicated prefix":
-                ns.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
-
-        // For now, we do not support separate IPv4 and IPv6 upstreams (e.g.
-        // tethering with 464xlat involved). TODO: Rectify this shortcoming,
-        // likely by calling NetworkManagementService#startInterfaceForwarding()
-        // for all upstream interfaces.
-        RouteInfo v4default = null;
-        RouteInfo v6default = null;
-        if (canTether) {
-            for (RouteInfo r : ns.linkProperties.getAllRoutes()) {
-                if (r.isIPv4Default()) {
-                    v4default = r;
-                } else if (r.isIPv6Default()) {
-                    v6default = r;
-                }
-
-                if (v4default != null && v6default != null) {
-                    break;
-                }
-            }
-        }
-
-        final boolean supportedConfiguration =
-                (v4default != null) && (v6default != null) &&
-                (v4default.getInterface() != null) &&
-                v4default.getInterface().equals(v6default.getInterface());
-
-        final boolean outcome = canTether && supportedConfiguration;
-
-        if (ns == null) {
-            sharedLog.log("No available upstream.");
-        } else {
-            sharedLog.log(String.format("IPv6 tethering is %s for upstream: %s",
-                    (outcome ? "available" : "not available"), toDebugString(ns)));
-        }
-
-        return outcome;
-    }
-
     private static LinkProperties getIPv6OnlyLinkProperties(LinkProperties lp) {
         final LinkProperties v6only = new LinkProperties();
         if (lp == null) {
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index 2224913..5ed14a0 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -31,7 +31,7 @@
 import android.net.ip.RouterAdvertisementDaemon;
 import android.net.ip.RouterAdvertisementDaemon.RaParams;
 import android.net.util.InterfaceParams;
-import android.net.util.NetdService;
+import android.net.util.InterfaceSet;
 import android.net.util.SharedLog;
 import android.os.INetworkManagementService;
 import android.os.Looper;
@@ -49,12 +49,12 @@
 
 import java.net.Inet6Address;
 import java.net.InetAddress;
-import java.net.SocketException;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Objects;
 import java.util.Random;
+import java.util.Set;
 
 /**
  * Provides the interface to IP-layer serving functionality for a given network
@@ -117,9 +117,11 @@
     private final int mInterfaceType;
     private final LinkProperties mLinkProperties;
 
+    private final TetheringDependencies mDeps;
+
     private int mLastError;
     private int mServingMode;
-    private String mMyUpstreamIfaceName;  // may change over time
+    private InterfaceSet mUpstreamIfaceSet;  // may change over time
     private InterfaceParams mInterfaceParams;
     // TODO: De-duplicate this with mLinkProperties above. Currently, these link
     // properties are those selected by the IPv6TetheringCoordinator and relayed
@@ -134,18 +136,19 @@
     public TetherInterfaceStateMachine(
             String ifaceName, Looper looper, int interfaceType, SharedLog log,
             INetworkManagementService nMService, INetworkStatsService statsService,
-            IControlsTethering tetherController) {
+            IControlsTethering tetherController,
+            TetheringDependencies deps) {
         super(ifaceName, looper);
         mLog = log.forSubComponent(ifaceName);
         mNMService = nMService;
-        // TODO: This should be passed in for testability.
-        mNetd = NetdService.getInstance();
+        mNetd = deps.getNetdService();
         mStatsService = statsService;
         mTetherController = tetherController;
         mInterfaceCtrl = new InterfaceController(ifaceName, nMService, mNetd, mLog);
         mIfaceName = ifaceName;
         mInterfaceType = interfaceType;
         mLinkProperties = new LinkProperties();
+        mDeps = deps;
         resetLinkProperties();
         mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
         mServingMode = IControlsTethering.STATE_AVAILABLE;
@@ -246,16 +249,14 @@
     }
 
     private boolean startIPv6() {
-        // TODO: Refactor for better testability.  This is one of the things
-        // that prohibits unittesting IPv6 tethering setup.
-        mInterfaceParams = InterfaceParams.getByName(mIfaceName);
+        mInterfaceParams = mDeps.getInterfaceParams(mIfaceName);
         if (mInterfaceParams == null) {
             mLog.e("Failed to find InterfaceParams");
             stopIPv6();
             return false;
         }
 
-        mRaDaemon = new RouterAdvertisementDaemon(mInterfaceParams);
+        mRaDaemon = mDeps.getRouterAdvertisementDaemon(mInterfaceParams);
         if (!mRaDaemon.start()) {
             stopIPv6();
             return false;
@@ -621,10 +622,10 @@
         }
 
         private void cleanupUpstream() {
-            if (mMyUpstreamIfaceName == null) return;
+            if (mUpstreamIfaceSet == null) return;
 
-            cleanupUpstreamInterface(mMyUpstreamIfaceName);
-            mMyUpstreamIfaceName = null;
+            for (String ifname : mUpstreamIfaceSet.ifnames) cleanupUpstreamInterface(ifname);
+            mUpstreamIfaceSet = null;
         }
 
         private void cleanupUpstreamInterface(String upstreamIface) {
@@ -660,34 +661,66 @@
                     mLog.e("CMD_TETHER_REQUESTED while already tethering.");
                     break;
                 case CMD_TETHER_CONNECTION_CHANGED:
-                    String newUpstreamIfaceName = (String)(message.obj);
-                    if ((mMyUpstreamIfaceName == null && newUpstreamIfaceName == null) ||
-                            (mMyUpstreamIfaceName != null &&
-                            mMyUpstreamIfaceName.equals(newUpstreamIfaceName))) {
+                    final InterfaceSet newUpstreamIfaceSet = (InterfaceSet) message.obj;
+                    if (noChangeInUpstreamIfaceSet(newUpstreamIfaceSet)) {
                         if (VDBG) Log.d(TAG, "Connection changed noop - dropping");
                         break;
                     }
-                    cleanupUpstream();
-                    if (newUpstreamIfaceName != null) {
+
+                    if (newUpstreamIfaceSet == null) {
+                        cleanupUpstream();
+                        break;
+                    }
+
+                    for (String removed : upstreamInterfacesRemoved(newUpstreamIfaceSet)) {
+                        cleanupUpstreamInterface(removed);
+                    }
+
+                    final Set<String> added = upstreamInterfacesAdd(newUpstreamIfaceSet);
+                    // This makes the call to cleanupUpstream() in the error
+                    // path for any interface neatly cleanup all the interfaces.
+                    mUpstreamIfaceSet = newUpstreamIfaceSet;
+
+                    for (String ifname : added) {
                         try {
-                            mNMService.enableNat(mIfaceName, newUpstreamIfaceName);
-                            mNMService.startInterfaceForwarding(mIfaceName,
-                                    newUpstreamIfaceName);
+                            mNMService.enableNat(mIfaceName, ifname);
+                            mNMService.startInterfaceForwarding(mIfaceName, ifname);
                         } catch (Exception e) {
                             mLog.e("Exception enabling NAT: " + e);
-                            cleanupUpstreamInterface(newUpstreamIfaceName);
+                            cleanupUpstream();
                             mLastError = ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
                             transitionTo(mInitialState);
                             return true;
                         }
                     }
-                    mMyUpstreamIfaceName = newUpstreamIfaceName;
                     break;
                 default:
                     return false;
             }
             return true;
         }
+
+        private boolean noChangeInUpstreamIfaceSet(InterfaceSet newIfaces) {
+            if (mUpstreamIfaceSet == null && newIfaces == null) return true;
+            if (mUpstreamIfaceSet != null && newIfaces != null) {
+                return mUpstreamIfaceSet.equals(newIfaces);
+            }
+            return false;
+        }
+
+        private Set<String> upstreamInterfacesRemoved(InterfaceSet newIfaces) {
+            if (mUpstreamIfaceSet == null) return new HashSet<>();
+
+            final HashSet<String> removed = new HashSet<>(mUpstreamIfaceSet.ifnames);
+            removed.removeAll(newIfaces.ifnames);
+            return removed;
+        }
+
+        private Set<String> upstreamInterfacesAdd(InterfaceSet newIfaces) {
+            final HashSet<String> added = new HashSet<>(newIfaces.ifnames);
+            if (mUpstreamIfaceSet != null) added.removeAll(mUpstreamIfaceSet.ifnames);
+            return added;
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
index b8174b6..66afb0f 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -16,9 +16,18 @@
 
 package com.android.server.connectivity.tethering;
 
+import android.content.Context;
+import android.net.INetd;
+import android.net.ip.RouterAdvertisementDaemon;
+import android.net.util.InterfaceParams;
+import android.net.util.NetdService;
 import android.os.Handler;
 import android.net.util.SharedLog;
 
+import com.android.internal.util.StateMachine;
+
+import java.util.ArrayList;
+
 
 /**
  * Capture tethering dependencies, for injection.
@@ -29,4 +38,26 @@
     public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) {
         return new OffloadHardwareInterface(h, log);
     }
+
+    public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx, StateMachine target,
+            SharedLog log, int what) {
+        return new UpstreamNetworkMonitor(ctx, target, log, what);
+    }
+
+    public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
+            ArrayList<TetherInterfaceStateMachine> notifyList, SharedLog log) {
+        return new IPv6TetheringCoordinator(notifyList, log);
+    }
+
+    public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
+        return new RouterAdvertisementDaemon(ifParams);
+    }
+
+    public InterfaceParams getInterfaceParams(String ifName) {
+        return InterfaceParams.getByName(ifName);
+    }
+
+    public INetd getNetdService() {
+        return NetdService.getInstance();
+    }
 }
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java b/services/core/java/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java
new file mode 100644
index 0000000..6c7ff91
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.tethering;
+
+import android.annotation.Nullable;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
+import android.net.NetworkState;
+import android.net.RouteInfo;
+import android.net.util.InterfaceSet;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+
+/**
+ * @hide
+ */
+public final class TetheringInterfaceUtils {
+    /**
+     * Get upstream interfaces for tethering based on default routes for IPv4/IPv6.
+     * @return null if there is no usable interface, or a set of at least one interface otherwise.
+     */
+    public static @Nullable InterfaceSet getTetheringInterfaces(NetworkState ns) {
+        if (ns == null) {
+            return null;
+        }
+
+        final LinkProperties lp = ns.linkProperties;
+        final String if4 = getInterfaceForDestination(lp, Inet4Address.ANY);
+        final String if6 = getIPv6Interface(ns);
+
+        return (if4 == null && if6 == null) ? null : new InterfaceSet(if4, if6);
+    }
+
+    /**
+     * Get the upstream interface for IPv6 tethering.
+     * @return null if there is no usable interface, or the interface name otherwise.
+     */
+    public static @Nullable String getIPv6Interface(NetworkState ns) {
+        // Broadly speaking:
+        //
+        //     [1] does the upstream have an IPv6 default route?
+        //
+        // and
+        //
+        //     [2] does the upstream have one or more global IPv6 /64s
+        //         dedicated to this device?
+        //
+        // In lieu of Prefix Delegation and other evaluation of whether a
+        // prefix may or may not be dedicated to this device, for now just
+        // check whether the upstream is TRANSPORT_CELLULAR. This works
+        // because "[t]he 3GPP network allocates each default bearer a unique
+        // /64 prefix", per RFC 6459, Section 5.2.
+        final boolean canTether =
+                (ns != null) && (ns.network != null) &&
+                (ns.linkProperties != null) && (ns.networkCapabilities != null) &&
+                // At least one upstream DNS server:
+                ns.linkProperties.hasIPv6DnsServer() &&
+                // Minimal amount of IPv6 provisioning:
+                ns.linkProperties.hasGlobalIPv6Address() &&
+                // Temporary approximation of "dedicated prefix":
+                ns.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
+
+        return canTether
+                ? getInterfaceForDestination(ns.linkProperties, Inet6Address.ANY)
+                : null;
+    }
+
+    private static String getInterfaceForDestination(LinkProperties lp, InetAddress dst) {
+        final RouteInfo ri = (lp != null)
+                ? RouteInfo.selectBestRoute(lp.getAllRoutes(), dst)
+                : null;
+        return (ri != null) ? ri.getInterface() : null;
+    }
+}
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 63308f8..ec404fe 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -26,6 +26,7 @@
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
+import android.content.ContentResolver.SyncExemption;
 import android.content.Context;
 import android.content.IContentService;
 import android.content.ISyncStatusObserver;
@@ -78,7 +79,7 @@
  */
 public final class ContentService extends IContentService.Stub {
     static final String TAG = "ContentService";
-    static final boolean DEBUG = false;
+    static final boolean DEBUG = true;
 
     public static class Lifecycle extends SystemService {
         private ContentService mService;
@@ -451,7 +452,7 @@
                 SyncManager syncManager = getSyncManager();
                 if (syncManager != null) {
                     syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle, uid,
-                            uri.getAuthority(), /*isAppStandbyExempted=*/ isUidInForeground(uid));
+                            uri.getAuthority(), getSyncExemptionForCaller(uid));
                 }
             }
 
@@ -508,7 +509,7 @@
         int uId = Binder.getCallingUid();
 
         validateExtras(uId, extras);
-        final boolean isForegroundSyncRequest = isForegroundSyncRequest(uId, extras);
+        final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(uId, extras);
 
         // This makes it so that future permission checks will be in the context of this
         // process rather than the caller's process. We will restore this before returning.
@@ -518,7 +519,7 @@
             if (syncManager != null) {
                 syncManager.scheduleSync(account, userId, uId, authority, extras,
                         SyncStorageEngine.AuthorityInfo.UNDEFINED,
-                        /*isAppStandbyExempted=*/ isForegroundSyncRequest);
+                        syncExemption);
             }
         } finally {
             restoreCallingIdentity(identityToken);
@@ -561,7 +562,7 @@
         final Bundle extras = request.getBundle();
 
         validateExtras(callerUid, extras);
-        final boolean isForegroundSyncRequest = isForegroundSyncRequest(callerUid, extras);
+        final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callerUid, extras);
 
         // This makes it so that future permission checks will be in the context of this
         // process rather than the caller's process. We will restore this before returning.
@@ -589,7 +590,7 @@
                 syncManager.scheduleSync(
                         request.getAccount(), userId, callerUid, request.getProvider(), extras,
                         SyncStorageEngine.AuthorityInfo.UNDEFINED,
-                        /*isAppStandbyExempted=*/ isForegroundSyncRequest);
+                        syncExemption);
             }
         } finally {
             restoreCallingIdentity(identityToken);
@@ -777,13 +778,15 @@
                 "no permission to write the sync settings");
         enforceCrossUserPermission(userId,
                 "no permission to modify the sync settings for user " + userId);
+        final int callingUid = Binder.getCallingUid();
+        final int syncExemptionFlag = getSyncExemptionForCaller(callingUid);
 
         long identityToken = clearCallingIdentity();
         try {
             SyncManager syncManager = getSyncManager();
             if (syncManager != null) {
                 syncManager.getSyncStorageEngine().setSyncAutomatically(account, userId,
-                        providerName, sync);
+                        providerName, sync, syncExemptionFlag);
             }
         } finally {
             restoreCallingIdentity(identityToken);
@@ -964,11 +967,14 @@
         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                 "no permission to write the sync settings");
 
+        final int callingUid = Binder.getCallingUid();
+
         long identityToken = clearCallingIdentity();
         try {
             SyncManager syncManager = getSyncManager();
             if (syncManager != null) {
-                syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId);
+                syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId,
+                        getSyncExemptionForCaller(callingUid));
             }
         } finally {
             restoreCallingIdentity(identityToken);
@@ -1263,9 +1269,7 @@
     }
 
     private void validateExtras(int callingUid, Bundle extras) {
-        if (extras.containsKey(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC)
-                || extras.containsKey(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC)
-                ) {
+        if (extras.containsKey(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG)) {
             switch (callingUid) {
                 case Process.ROOT_UID:
                 case Process.SHELL_UID:
@@ -1277,39 +1281,36 @@
         }
     }
 
-    private boolean isForegroundSyncRequest(int callingUid, Bundle extras) {
-        final boolean isForegroundRequest;
-        if (extras.getBoolean(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC)) {
-            isForegroundRequest = true;
-        } else if (extras.getBoolean(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_BG_SYNC)) {
-            isForegroundRequest = false;
-        } else {
-            isForegroundRequest = isUidInForeground(callingUid);
-        }
-        extras.remove(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC);
-        extras.remove(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_BG_SYNC);
-
-        return isForegroundRequest;
+    @SyncExemption
+    private int getSyncExemptionForCaller(int callingUid) {
+        return getSyncExemptionAndCleanUpExtrasForCaller(callingUid, null);
     }
 
-    private boolean isUidInForeground(int uid) {
-        // If the caller is ADB, we assume it's a background request by default, because
-        // that's also the default of requests from the requestsync command.
-        // The requestsync command will always set either SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC or
-        // SYNC_VIRTUAL_EXTRAS_FORCE_BG_SYNC (for non-periodic sync requests),
-        // so it shouldn't matter in practice.
-        switch (uid) {
-            case Process.SHELL_UID:
-            case Process.ROOT_UID:
-                return false;
+    @SyncExemption
+    private int getSyncExemptionAndCleanUpExtrasForCaller(int callingUid, Bundle extras) {
+        if (extras != null) {
+            final int exemption =
+                    extras.getInt(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG, -1);
+
+            // Need to remove the virtual extra.
+            extras.remove(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG);
+            if (exemption != -1) {
+                return exemption;
+            }
         }
         final ActivityManagerInternal ami =
                 LocalServices.getService(ActivityManagerInternal.class);
-        if (ami != null) {
-            return ami.getUidProcessState(uid)
-                    <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+        final int procState = (ami != null)
+                ? ami.getUidProcessState(callingUid)
+                : ActivityManager.PROCESS_STATE_NONEXISTENT;
+
+        if (procState <= ActivityManager.PROCESS_STATE_TOP) {
+            return ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP;
         }
-        return false;
+        if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
+            return ContentResolver.SYNC_EXEMPTION_ACTIVE;
+        }
+        return ContentResolver.SYNC_EXEMPTION_NONE;
     }
 
     /**
diff --git a/services/core/java/com/android/server/content/SyncAdapterStateFetcher.java b/services/core/java/com/android/server/content/SyncAdapterStateFetcher.java
new file mode 100644
index 0000000..62fb751
--- /dev/null
+++ b/services/core/java/com/android/server/content/SyncAdapterStateFetcher.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.content;
+
+import android.app.usage.UsageStatsManagerInternal;
+import android.os.SystemClock;
+import android.util.Pair;
+
+import com.android.server.AppStateTracker;
+import com.android.server.LocalServices;
+
+import java.util.HashMap;
+
+class SyncAdapterStateFetcher {
+
+    private final HashMap<Pair<Integer, String>, Integer> mBucketCache =
+            new HashMap<>();
+
+    public SyncAdapterStateFetcher() {
+    }
+
+    /**
+     * Return sync adapter state with a cache.
+     */
+    public int getStandbyBucket(int userId, String packageName) {
+        final Pair<Integer, String> key = Pair.create(userId, packageName);
+        final Integer cached = mBucketCache.get(key);
+        if (cached != null) {
+            return cached;
+        }
+        final UsageStatsManagerInternal usmi =
+                LocalServices.getService(UsageStatsManagerInternal.class);
+        if (usmi == null) {
+            return -1; // Unknown.
+        }
+
+        final int value = usmi.getAppStandbyBucket(packageName, userId,
+                SystemClock.elapsedRealtime());
+        mBucketCache.put(key, value);
+        return value;
+    }
+
+    /**
+     * Return UID active state.
+     */
+    public boolean isAppActive(int uid) {
+        final AppStateTracker ast =
+                LocalServices.getService(AppStateTracker.class);
+        if (ast == null) {
+            return false;
+        }
+
+        return ast.isUidActive(uid);
+    }
+}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 7089268..d1f50b7 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -29,9 +29,11 @@
 import android.app.PendingIntent;
 import android.app.job.JobInfo;
 import android.app.job.JobScheduler;
+import android.app.usage.UsageStatsManagerInternal;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
+import android.content.ContentResolver.SyncExemption;
 import android.content.Context;
 import android.content.ISyncAdapter;
 import android.content.ISyncAdapterUnsyncableAccountCallback;
@@ -70,6 +72,7 @@
 import android.os.Message;
 import android.os.Messenger;
 import android.os.PowerManager;
+import android.os.Process;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -88,6 +91,8 @@
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.util.ArrayUtils;
+import com.android.server.DeviceIdleController;
+import com.android.server.DeviceIdleController.LocalService;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.job.JobSchedulerInternal;
@@ -550,10 +555,6 @@
         return mJobScheduler;
     }
 
-    /**
-     * Should only be created after {@link ContentService#systemReady()} so that
-     * {@link PackageManager} is ready to query.
-     */
     public SyncManager(Context context, boolean factoryTest) {
         // Initialize the SyncStorageEngine first, before registering observers
         // and creating threads and so on; it may fail if the disk is full.
@@ -566,9 +567,9 @@
         mSyncStorageEngine.setOnSyncRequestListener(new OnSyncRequestListener() {
             @Override
             public void onSyncRequest(SyncStorageEngine.EndPoint info, int reason, Bundle extras,
-                    boolean isAppStandbyExempted) {
+                    @SyncExemption int syncExemptionFlag) {
                 scheduleSync(info.account, info.userId, reason, info.provider, extras,
-                        AuthorityInfo.UNDEFINED, isAppStandbyExempted);
+                        AuthorityInfo.UNDEFINED, syncExemptionFlag);
             }
         });
 
@@ -599,7 +600,7 @@
                     scheduleSync(null, UserHandle.USER_ALL,
                             SyncOperation.REASON_SERVICE_CHANGED,
                             type.authority, null, AuthorityInfo.UNDEFINED,
-                            /*isAppStandbyExempted=*/ false);
+                            ContentResolver.SYNC_EXEMPTION_NONE);
                 }
             }
         }, mSyncHandler);
@@ -649,7 +650,7 @@
                 scheduleSync(account, UserHandle.getUserId(uid),
                         SyncOperation.REASON_ACCOUNTS_UPDATED,
                         null, null, AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS,
-                        /*isAppStandbyExempted=*/ false);
+                        ContentResolver.SYNC_EXEMPTION_NONE);
             }
         });
 
@@ -883,9 +884,9 @@
      */
     public void scheduleSync(Account requestedAccount, int userId, int reason,
             String requestedAuthority, Bundle extras, int targetSyncState,
-            boolean isAppStandbyExempted) {
+            @SyncExemption int syncExemptionFlag) {
         scheduleSync(requestedAccount, userId, reason, requestedAuthority, extras, targetSyncState,
-                0 /* min delay */, true /* checkIfAccountReady */, isAppStandbyExempted);
+                0 /* min delay */, true /* checkIfAccountReady */, syncExemptionFlag);
     }
 
     /**
@@ -894,7 +895,7 @@
     private void scheduleSync(Account requestedAccount, int userId, int reason,
             String requestedAuthority, Bundle extras, int targetSyncState,
             final long minDelayMillis, boolean checkIfAccountReady,
-            boolean isAppStandbyExempted) {
+            @SyncExemption int syncExemptionFlag) {
         final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
         if (extras == null) {
             extras = new Bundle();
@@ -904,7 +905,7 @@
                     + requestedAuthority
                     + " reason=" + reason
                     + " checkIfAccountReady=" + checkIfAccountReady
-                    + " isAppStandbyExempted=" + isAppStandbyExempted);
+                    + " syncExemptionFlag=" + syncExemptionFlag);
         }
 
         AccountAndUser[] accounts = null;
@@ -1016,7 +1017,7 @@
                                     scheduleSync(account.account, userId, reason, authority,
                                             finalExtras, targetSyncState, minDelayMillis,
                                             true /* checkIfAccountReady */,
-                                            isAppStandbyExempted);
+                                            syncExemptionFlag);
                                 }
                             }
                         ));
@@ -1067,7 +1068,7 @@
                         sendOnUnsyncableAccount(mContext, syncAdapterInfo, account.userId,
                                 () -> scheduleSync(account.account, account.userId, reason,
                                         authority, finalExtras, targetSyncState, minDelayMillis,
-                                        false, isAppStandbyExempted));
+                                        false, syncExemptionFlag));
                     } else {
                         // Initialisation sync.
                         Bundle newExtras = new Bundle();
@@ -1086,7 +1087,7 @@
                                 new SyncOperation(account.account, account.userId,
                                         owningUid, owningPackage, reason, source,
                                         authority, newExtras, allowParallelSyncs,
-                                        isAppStandbyExempted),
+                                        syncExemptionFlag),
                                 minDelayMillis
                         );
                     }
@@ -1103,7 +1104,7 @@
                     postScheduleSyncMessage(
                             new SyncOperation(account.account, account.userId,
                                     owningUid, owningPackage, reason, source,
-                                    authority, extras, allowParallelSyncs, isAppStandbyExempted),
+                                    authority, extras, allowParallelSyncs, syncExemptionFlag),
                             minDelayMillis
                     );
                 }
@@ -1217,12 +1218,12 @@
      * ms to batch syncs.
      */
     public void scheduleLocalSync(Account account, int userId, int reason, String authority,
-            boolean isAppStandbyExempted) {
+            @SyncExemption int syncExemptionFlag) {
         final Bundle extras = new Bundle();
         extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
         scheduleSync(account, userId, reason, authority, extras,
                 AuthorityInfo.UNDEFINED, LOCAL_SYNC_DELAY, true /* checkIfAccountReady */,
-                isAppStandbyExempted);
+                syncExemptionFlag);
     }
 
     public SyncAdapterType[] getSyncAdapterTypes(int userId) {
@@ -1493,7 +1494,7 @@
 
         // If any of the duplicate ones has exemption, then we inherit it.
         if (!syncOperation.isPeriodic) {
-            boolean inheritAppStandbyExemption = false;
+            int inheritedSyncExemptionFlag = ContentResolver.SYNC_EXEMPTION_NONE;
 
             // Check currently running syncs
             for (ActiveSyncContext asc: mActiveSyncContexts) {
@@ -1534,10 +1535,11 @@
                 // This means the duplicate one has a negative expected run time, but it hasn't
                 // been executed possibly because of app-standby.
 
-                if (syncOperation.isAppStandbyExempted
-                        && (minDelay == 0)
-                        && !syncToRun.isAppStandbyExempted) {
+                if ((minDelay == 0)
+                        && (syncToRun.syncExemptionFlag < syncOperation.syncExemptionFlag)) {
                     syncToRun = syncOperation;
+                    inheritedSyncExemptionFlag =
+                            Math.max(inheritedSyncExemptionFlag, syncToRun.syncExemptionFlag);
                 }
             }
 
@@ -1551,9 +1553,8 @@
                         if (isLoggable) {
                             Slog.v(TAG, "Cancelling duplicate sync " + op);
                         }
-                        if (op.isAppStandbyExempted) {
-                            inheritAppStandbyExemption = true;
-                        }
+                        inheritedSyncExemptionFlag =
+                                Math.max(inheritedSyncExemptionFlag, op.syncExemptionFlag);
                         cancelJob(op, "scheduleSyncOperationH-duplicate");
                     }
                 }
@@ -1570,8 +1571,9 @@
             }
 
             // If any of the duplicates had exemption, we exempt the current one.
-            if (inheritAppStandbyExemption) {
-                syncOperation.isAppStandbyExempted = true;
+            //
+            if (inheritedSyncExemptionFlag > ContentResolver.SYNC_EXEMPTION_NONE) {
+                syncOperation.syncExemptionFlag = inheritedSyncExemptionFlag;
             }
         }
 
@@ -1591,7 +1593,7 @@
 
         // Note this logic means when an exempted sync fails,
         // the back-off one will inherit it too, and will be exempted from app-standby.
-        final int jobFlags = syncOperation.isAppStandbyExempted
+        final int jobFlags = syncOperation.isAppStandbyExempted()
                 ? JobInfo.FLAG_EXEMPT_FROM_APP_STANDBY : 0;
 
         JobInfo.Builder b = new JobInfo.Builder(syncOperation.jobId,
@@ -1615,6 +1617,19 @@
             b.setRequiresCharging(true);
         }
 
+        if (syncOperation.syncExemptionFlag
+                == ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP) {
+            DeviceIdleController.LocalService dic =
+                    LocalServices.getService(DeviceIdleController.LocalService.class);
+            if (dic != null) {
+                dic.addPowerSaveTempWhitelistApp(Process.SYSTEM_UID,
+                        syncOperation.owningPackage,
+                        mConstants.getKeyExemptionTempWhitelistDurationInSeconds() * 1000,
+                        UserHandle.getUserId(syncOperation.owningUid),
+                        /* sync=*/ false, "sync by top app");
+            }
+        }
+
         getJobScheduler().scheduleAsPackage(b.build(), syncOperation.owningPackage,
                 syncOperation.target.userId, syncOperation.wakeLockName());
     }
@@ -1736,7 +1751,7 @@
                 mContext.getOpPackageName());
         for (Account account : accounts) {
             scheduleSync(account, userId, SyncOperation.REASON_USER_START, null, null,
-                    AuthorityInfo.NOT_INITIALIZED, /*isAppStandbyExempted=*/ false);
+                    AuthorityInfo.NOT_INITIALIZED, ContentResolver.SYNC_EXEMPTION_NONE);
         }
     }
 
@@ -1930,7 +1945,10 @@
 
     protected void dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
         final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
-        dumpSyncState(ipw);
+
+        final SyncAdapterStateFetcher buckets = new SyncAdapterStateFetcher();
+
+        dumpSyncState(ipw, buckets);
         mConstants.dump(pw, "");
         dumpSyncAdapters(ipw);
 
@@ -1991,7 +2009,7 @@
         return ret;
     }
 
-    protected void dumpPendingSyncs(PrintWriter pw) {
+    protected void dumpPendingSyncs(PrintWriter pw, SyncAdapterStateFetcher buckets) {
         List<SyncOperation> pendingSyncs = getAllPendingSyncs();
 
         pw.print("Pending Syncs: ");
@@ -2001,14 +2019,14 @@
         int count = 0;
         for (SyncOperation op: pendingSyncs) {
             if (!op.isPeriodic) {
-                pw.println(op.dump(null, false));
+                pw.println(op.dump(null, false, buckets));
                 count++;
             }
         }
         pw.println();
     }
 
-    protected void dumpPeriodicSyncs(PrintWriter pw) {
+    protected void dumpPeriodicSyncs(PrintWriter pw, SyncAdapterStateFetcher buckets) {
         List<SyncOperation> pendingSyncs = getAllPendingSyncs();
 
         pw.print("Periodic Syncs: ");
@@ -2018,7 +2036,7 @@
         int count = 0;
         for (SyncOperation op: pendingSyncs) {
             if (op.isPeriodic) {
-                pw.println(op.dump(null, false));
+                pw.println(op.dump(null, false, buckets));
                 count++;
             }
         }
@@ -2075,7 +2093,7 @@
         return true;
     }
 
-    protected void dumpSyncState(PrintWriter pw) {
+    protected void dumpSyncState(PrintWriter pw, SyncAdapterStateFetcher buckets) {
         final StringBuilder sb = new StringBuilder();
 
         pw.print("Data connected: "); pw.println(mDataConnectionIsConnected);
@@ -2150,13 +2168,13 @@
             sb.setLength(0);
             pw.print(formatDurationHMS(sb, durationInSeconds));
             pw.print(" - ");
-            pw.print(activeSyncContext.mSyncOperation.dump(pm, false));
+            pw.print(activeSyncContext.mSyncOperation.dump(pm, false, buckets));
             pw.println();
         }
         pw.println();
 
-        dumpPendingSyncs(pw);
-        dumpPeriodicSyncs(pw);
+        dumpPendingSyncs(pw, buckets);
+        dumpPeriodicSyncs(pw, buckets);
 
         // Join the installed sync adapter with the accounts list and emit for everything.
         pw.println("Sync Status");
@@ -3219,7 +3237,7 @@
                 scheduleSync(syncTargets.account, syncTargets.userId,
                         SyncOperation.REASON_ACCOUNTS_UPDATED, syncTargets.provider,
                         null, AuthorityInfo.NOT_INITIALIZED,
-                        /*isAppStandbyExempted=*/ false);
+                        ContentResolver.SYNC_EXEMPTION_NONE);
             }
         }
 
@@ -3286,7 +3304,7 @@
                     syncAdapterInfo.componentName.getPackageName(), SyncOperation.REASON_PERIODIC,
                     SyncStorageEngine.SOURCE_PERIODIC, extras,
                     syncAdapterInfo.type.allowParallelSyncs(), true, SyncOperation.NO_JOB_ID,
-                    pollFrequencyMillis, flexMillis, /*isAppStandbyExempted=*/ false);
+                    pollFrequencyMillis, flexMillis, ContentResolver.SYNC_EXEMPTION_NONE);
 
             final int syncOpState = computeSyncOpState(op);
             switch (syncOpState) {
@@ -3431,6 +3449,15 @@
                     Slog.v(TAG, syncContext.toString());
                 }
             }
+            if (op.isAppStandbyExempted()) {
+                final UsageStatsManagerInternal usmi = LocalServices.getService(
+                        UsageStatsManagerInternal.class);
+                if (usmi != null) {
+                    usmi.reportExemptedSyncStart(op.owningPackage,
+                            UserHandle.getUserId(op.owningUid));
+                }
+            }
+
             // Connect to the sync adapter.
             int targetUid;
             ComponentName targetComponent;
@@ -3604,7 +3631,7 @@
 
                     syncOperation.retries++;
                     if (syncOperation.retries > mConstants.getMaxRetriesWithAppStandbyExemption()) {
-                        syncOperation.isAppStandbyExempted = false;
+                        syncOperation.syncExemptionFlag = ContentResolver.SYNC_EXEMPTION_NONE;
                     }
 
                     // the operation failed so increase the backoff time
@@ -3672,7 +3699,7 @@
                                 syncOperation.reason,
                                 syncOperation.syncSource, info.provider, new Bundle(),
                                 syncOperation.allowParallelSyncs,
-                                syncOperation.isAppStandbyExempted));
+                                syncOperation.syncExemptionFlag));
             }
         }
 
diff --git a/services/core/java/com/android/server/content/SyncManagerConstants.java b/services/core/java/com/android/server/content/SyncManagerConstants.java
index 061e4ca..2a5858c 100644
--- a/services/core/java/com/android/server/content/SyncManagerConstants.java
+++ b/services/core/java/com/android/server/content/SyncManagerConstants.java
@@ -52,6 +52,12 @@
     private static final int DEF_MAX_RETRIES_WITH_APP_STANDBY_EXEMPTION = 5;
     private int mMaxRetriesWithAppStandbyExemption = DEF_MAX_RETRIES_WITH_APP_STANDBY_EXEMPTION;
 
+    private static final String KEY_EXEMPTION_TEMP_WHITELIST_DURATION_IN_SECONDS =
+            "exemption_temp_whitelist_duration_in_seconds";
+    private static final int DEF_EXEMPTION_TEMP_WHITELIST_DURATION_IN_SECONDS = 10 * 60;
+    private int mKeyExemptionTempWhitelistDurationInSeconds
+            = DEF_EXEMPTION_TEMP_WHITELIST_DURATION_IN_SECONDS;
+
     protected SyncManagerConstants(Context context) {
         super(null);
         mContext = context;
@@ -97,6 +103,11 @@
             mMaxRetriesWithAppStandbyExemption = parser.getInt(
                     KEY_MAX_RETRIES_WITH_APP_STANDBY_EXEMPTION,
                     DEF_MAX_RETRIES_WITH_APP_STANDBY_EXEMPTION);
+
+            mKeyExemptionTempWhitelistDurationInSeconds = parser.getInt(
+                    KEY_EXEMPTION_TEMP_WHITELIST_DURATION_IN_SECONDS,
+                    DEF_EXEMPTION_TEMP_WHITELIST_DURATION_IN_SECONDS);
+
         }
     }
 
@@ -124,6 +135,12 @@
         }
     }
 
+    public int getKeyExemptionTempWhitelistDurationInSeconds() {
+        synchronized (mLock) {
+            return mKeyExemptionTempWhitelistDurationInSeconds;
+        }
+    }
+
     public void dump(PrintWriter pw, String prefix) {
         synchronized (mLock) {
             pw.print(prefix);
@@ -144,6 +161,10 @@
             pw.print(prefix);
             pw.print("  mMaxRetriesWithAppStandbyExemption=");
             pw.println(mMaxRetriesWithAppStandbyExemption);
+
+            pw.print(prefix);
+            pw.print("  mKeyExemptionTempWhitelistDurationInSeconds=");
+            pw.println(mKeyExemptionTempWhitelistDurationInSeconds);
         }
     }
 }
diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java
index 96bdaea..d097563 100644
--- a/services/core/java/com/android/server/content/SyncOperation.java
+++ b/services/core/java/com/android/server/content/SyncOperation.java
@@ -19,6 +19,7 @@
 import android.accounts.Account;
 import android.app.job.JobInfo;
 import android.content.ContentResolver;
+import android.content.ContentResolver.SyncExemption;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.os.PersistableBundle;
@@ -98,33 +99,33 @@
     /** jobId of the JobScheduler job corresponding to this sync */
     public int jobId;
 
-    /** Whether this operation should be exempted from the app-standby throttling. */
-    public boolean isAppStandbyExempted;
+    @SyncExemption
+    public int syncExemptionFlag;
 
     public SyncOperation(Account account, int userId, int owningUid, String owningPackage,
                          int reason, int source, String provider, Bundle extras,
-                         boolean allowParallelSyncs, boolean isAppStandbyExempted) {
+                         boolean allowParallelSyncs, @SyncExemption int syncExemptionFlag) {
         this(new SyncStorageEngine.EndPoint(account, provider, userId), owningUid, owningPackage,
-                reason, source, extras, allowParallelSyncs, isAppStandbyExempted);
+                reason, source, extras, allowParallelSyncs, syncExemptionFlag);
     }
 
     private SyncOperation(SyncStorageEngine.EndPoint info, int owningUid, String owningPackage,
             int reason, int source, Bundle extras, boolean allowParallelSyncs,
-            boolean isAppStandbyExempted) {
+            @SyncExemption int syncExemptionFlag) {
         this(info, owningUid, owningPackage, reason, source, extras, allowParallelSyncs, false,
-                NO_JOB_ID, 0, 0, isAppStandbyExempted);
+                NO_JOB_ID, 0, 0, syncExemptionFlag);
     }
 
     public SyncOperation(SyncOperation op, long periodMillis, long flexMillis) {
         this(op.target, op.owningUid, op.owningPackage, op.reason, op.syncSource,
                 new Bundle(op.extras), op.allowParallelSyncs, op.isPeriodic, op.sourcePeriodicId,
-                periodMillis, flexMillis, /*isAppStandbyExempted=*/ false);
+                periodMillis, flexMillis, ContentResolver.SYNC_EXEMPTION_NONE);
     }
 
     public SyncOperation(SyncStorageEngine.EndPoint info, int owningUid, String owningPackage,
                          int reason, int source, Bundle extras, boolean allowParallelSyncs,
                          boolean isPeriodic, int sourcePeriodicId, long periodMillis,
-                         long flexMillis, boolean isAppStandbyExempted) {
+                         long flexMillis, @SyncExemption int syncExemptionFlag) {
         this.target = info;
         this.owningUid = owningUid;
         this.owningPackage = owningPackage;
@@ -138,7 +139,7 @@
         this.flexMillis = flexMillis;
         this.jobId = NO_JOB_ID;
         this.key = toKey();
-        this.isAppStandbyExempted = isAppStandbyExempted;
+        this.syncExemptionFlag = syncExemptionFlag;
     }
 
     /* Get a one off sync operation instance from a periodic sync. */
@@ -148,7 +149,7 @@
         }
         SyncOperation op = new SyncOperation(target, owningUid, owningPackage, reason, syncSource,
                 new Bundle(extras), allowParallelSyncs, false, jobId /* sourcePeriodicId */,
-                periodMillis, flexMillis, /*isAppStandbyExempted=*/ false);
+                periodMillis, flexMillis, ContentResolver.SYNC_EXEMPTION_NONE);
         return op;
     }
 
@@ -166,7 +167,7 @@
         periodMillis = other.periodMillis;
         flexMillis = other.flexMillis;
         this.key = other.key;
-        isAppStandbyExempted = other.isAppStandbyExempted;
+        syncExemptionFlag = other.syncExemptionFlag;
     }
 
     /**
@@ -235,7 +236,7 @@
         jobInfoExtras.putLong("flexMillis", flexMillis);
         jobInfoExtras.putLong("expectedRuntime", expectedRuntime);
         jobInfoExtras.putInt("retries", retries);
-        jobInfoExtras.putBoolean("isAppStandbyExempted", isAppStandbyExempted);
+        jobInfoExtras.putInt("syncExemptionFlag", syncExemptionFlag);
         return jobInfoExtras;
     }
 
@@ -256,7 +257,7 @@
         Bundle extras;
         boolean allowParallelSyncs, isPeriodic;
         long periodMillis, flexMillis;
-        boolean isAppStandbyExempted;
+        int syncExemptionFlag;
 
         if (!jobExtras.getBoolean("SyncManagerJob", false)) {
             return null;
@@ -275,7 +276,8 @@
         initiatedBy = jobExtras.getInt("sourcePeriodicId", NO_JOB_ID);
         periodMillis = jobExtras.getLong("periodMillis");
         flexMillis = jobExtras.getLong("flexMillis");
-        isAppStandbyExempted = jobExtras.getBoolean("isAppStandbyExempted", false);
+        syncExemptionFlag = jobExtras.getInt("syncExemptionFlag",
+                ContentResolver.SYNC_EXEMPTION_NONE);
         extras = new Bundle();
 
         PersistableBundle syncExtras = jobExtras.getPersistableBundle("syncExtras");
@@ -298,7 +300,7 @@
                 new SyncStorageEngine.EndPoint(account, provider, userId);
         SyncOperation op = new SyncOperation(target, owningUid, owningPackage, reason, source,
                 extras, allowParallelSyncs, isPeriodic, initiatedBy, periodMillis, flexMillis,
-                isAppStandbyExempted);
+                syncExemptionFlag);
         op.jobId = jobExtras.getInt("jobId");
         op.expectedRuntime = jobExtras.getLong("expectedRuntime");
         op.retries = jobExtras.getInt("retries");
@@ -361,10 +363,10 @@
 
     @Override
     public String toString() {
-        return dump(null, true);
+        return dump(null, true, null);
     }
 
-    String dump(PackageManager pm, boolean shorter) {
+    String dump(PackageManager pm, boolean shorter, SyncAdapterStateFetcher appStates) {
         StringBuilder sb = new StringBuilder();
         sb.append("JobId=").append(jobId)
                 .append(" ")
@@ -385,8 +387,18 @@
         if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)) {
             sb.append(" EXPEDITED");
         }
-        if (isAppStandbyExempted) {
-            sb.append(" STANDBY-EXEMPTED");
+        switch (syncExemptionFlag) {
+            case ContentResolver.SYNC_EXEMPTION_NONE:
+                break;
+            case ContentResolver.SYNC_EXEMPTION_ACTIVE:
+                sb.append(" STANDBY-EXEMPTED");
+                break;
+            case ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP:
+                sb.append(" STANDBY-EXEMPTED(TOP)");
+                break;
+            default:
+                sb.append(" ExemptionFlag=" + syncExemptionFlag);
+                break;
         }
         sb.append(" Reason=");
         sb.append(reasonToString(pm, reason));
@@ -397,21 +409,31 @@
             SyncManager.formatDurationHMS(sb, flexMillis);
             sb.append(")");
         }
+        if (retries > 0) {
+            sb.append(" Retries=");
+            sb.append(retries);
+        }
         if (!shorter) {
             sb.append(" Owner={");
             UserHandle.formatUid(sb, owningUid);
             sb.append(" ");
             sb.append(owningPackage);
+            if (appStates != null) {
+                sb.append(" [");
+                sb.append(appStates.getStandbyBucket(
+                        UserHandle.getUserId(owningUid), owningPackage));
+                sb.append("]");
+
+                if (appStates.isAppActive(owningUid)) {
+                    sb.append(" [ACTIVE]");
+                }
+            }
             sb.append("}");
             if (!extras.keySet().isEmpty()) {
                 sb.append(" ");
                 extrasToStringBuilder(extras, sb);
             }
         }
-        if (retries > 0) {
-            sb.append(" Retries=");
-            sb.append(retries);
-        }
         return sb.toString();
     }
 
@@ -464,6 +486,10 @@
         return extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false);
     }
 
+    boolean isAppStandbyExempted() {
+        return syncExemptionFlag != ContentResolver.SYNC_EXEMPTION_NONE;
+    }
+
     static void extrasToStringBuilder(Bundle bundle, StringBuilder sb) {
         if (bundle == null) {
             sb.append("null");
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 8b67b7a..6081af8 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -22,6 +22,7 @@
 import android.app.backup.BackupManager;
 import android.content.ComponentName;
 import android.content.ContentResolver;
+import android.content.ContentResolver.SyncExemption;
 import android.content.Context;
 import android.content.ISyncStatusObserver;
 import android.content.PeriodicSync;
@@ -341,7 +342,7 @@
 
         /** Called when a sync is needed on an account(s) due to some change in state. */
         public void onSyncRequest(EndPoint info, int reason, Bundle extras,
-                boolean exemptFromAppStandby);
+                @SyncExemption int syncExemptionFlag);
     }
 
     interface PeriodicSyncAddedListener {
@@ -647,7 +648,7 @@
     }
 
     public void setSyncAutomatically(Account account, int userId, String providerName,
-                                     boolean sync) {
+                                     boolean sync, @SyncExemption int syncExemptionFlag) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Slog.d(TAG, "setSyncAutomatically: " + /* account + */" provider " + providerName
                     + ", user " + userId + " -> " + sync);
@@ -677,7 +678,7 @@
         if (sync) {
             requestSync(account, userId, SyncOperation.REASON_SYNC_AUTO, providerName,
                     new Bundle(),
-                    /* exemptFromAppStandby=*/ false);
+                    syncExemptionFlag);
         }
         reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
         queueBackup();
@@ -739,7 +740,7 @@
         }
         if (syncable == AuthorityInfo.SYNCABLE) {
             requestSync(aInfo, SyncOperation.REASON_IS_SYNCABLE, new Bundle(),
-                    /*exemptFromAppStandby=*/ false); // Or the caller FG state?
+                    ContentResolver.SYNC_EXEMPTION_NONE);
         }
         reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
     }
@@ -900,7 +901,8 @@
         return true;
     }
 
-    public void setMasterSyncAutomatically(boolean flag, int userId) {
+    public void setMasterSyncAutomatically(boolean flag, int userId,
+            @SyncExemption int syncExemptionFlag) {
         synchronized (mAuthorities) {
             Boolean auto = mMasterSyncAutomatically.get(userId);
             if (auto != null && auto.equals(flag)) {
@@ -912,7 +914,7 @@
         if (flag) {
             requestSync(null, userId, SyncOperation.REASON_MASTER_SYNC_AUTO, null,
                     new Bundle(),
-                    /*exemptFromAppStandby=*/ false); // Or the caller FG state?
+                    syncExemptionFlag);
         }
         reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
         mContext.sendBroadcast(ContentResolver.ACTION_SYNC_CONN_STATUS_CHANGED);
@@ -2046,7 +2048,8 @@
                 String value = c.getString(c.getColumnIndex("value"));
                 if (name == null) continue;
                 if (name.equals("listen_for_tickles")) {
-                    setMasterSyncAutomatically(value == null || Boolean.parseBoolean(value), 0);
+                    setMasterSyncAutomatically(value == null || Boolean.parseBoolean(value), 0,
+                            ContentResolver.SYNC_EXEMPTION_NONE);
                 } else if (name.startsWith("sync_provider_")) {
                     String provider = name.substring("sync_provider_".length(),
                             name.length());
@@ -2143,11 +2146,11 @@
     }
 
     private void requestSync(AuthorityInfo authorityInfo, int reason, Bundle extras,
-            boolean exemptFromAppStandby) {
+            @SyncExemption int syncExemptionFlag) {
         if (android.os.Process.myUid() == android.os.Process.SYSTEM_UID
                 && mSyncRequestListener != null) {
             mSyncRequestListener.onSyncRequest(authorityInfo.target, reason, extras,
-                    exemptFromAppStandby);
+                    syncExemptionFlag);
         } else {
             SyncRequest.Builder req =
                     new SyncRequest.Builder()
@@ -2159,7 +2162,7 @@
     }
 
     private void requestSync(Account account, int userId, int reason, String authority,
-            Bundle extras, boolean exemptFromAppStandby) {
+            Bundle extras, @SyncExemption int syncExemptionFlag) {
         // If this is happening in the system process, then call the syncrequest listener
         // to make a request back to the SyncManager directly.
         // If this is probably a test instance, then call back through the ContentResolver
@@ -2168,7 +2171,7 @@
                 && mSyncRequestListener != null) {
             mSyncRequestListener.onSyncRequest(
                     new EndPoint(account, authority, userId),
-                    reason, extras, exemptFromAppStandby);
+                    reason, extras, syncExemptionFlag);
         } else {
             ContentResolver.requestSync(account, authority, extras);
         }
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index c4b2b5e..c7ae1f4 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -695,6 +695,27 @@
         }
     }
 
+    private void setSaturationLevelInternal(float level) {
+        if (level < 0 || level > 1) {
+            throw new IllegalArgumentException("Saturation level must be between 0 and 1");
+        }
+        float[] matrix = (level == 1.0f ? null : computeSaturationMatrix(level));
+        DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
+        dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_SATURATION, matrix);
+    }
+
+    private static float[] computeSaturationMatrix(float saturation) {
+        float desaturation = 1.0f - saturation;
+        float[] luminance = {0.231f * desaturation, 0.715f * desaturation, 0.072f * desaturation};
+        float[] matrix = {
+            luminance[0] + saturation, luminance[0], luminance[0], 0,
+            luminance[1], luminance[1] + saturation, luminance[1], 0,
+            luminance[2], luminance[2], luminance[2] + saturation, 0,
+            0, 0, 0, 1
+        };
+        return matrix;
+    }
+
     private int createVirtualDisplayInternal(IVirtualDisplayCallback callback,
             IMediaProjection projection, int callingUid, String packageName, String name, int width,
             int height, int densityDpi, Surface surface, int flags, String uniqueId) {
@@ -1687,6 +1708,19 @@
         }
 
         @Override // Binder call
+        public void setSaturationLevel(float level) {
+            mContext.enforceCallingOrSelfPermission(
+                   Manifest.permission.CONTROL_DISPLAY_SATURATION,
+                   "Permission required to set display saturation level");
+            final long token = Binder.clearCallingIdentity();
+            try {
+                setSaturationLevelInternal(level);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
         public int createVirtualDisplay(IVirtualDisplayCallback callback,
                 IMediaProjection projection, String packageName, String name,
                 int width, int height, int densityDpi, Surface surface, int flags,
diff --git a/services/core/java/com/android/server/display/DisplayTransformManager.java b/services/core/java/com/android/server/display/DisplayTransformManager.java
index 000fcf3..a94f049 100644
--- a/services/core/java/com/android/server/display/DisplayTransformManager.java
+++ b/services/core/java/com/android/server/display/DisplayTransformManager.java
@@ -17,7 +17,6 @@
 package com.android.server.display;
 
 import android.app.ActivityManager;
-import android.app.IActivityManager;
 import android.opengl.Matrix;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -28,7 +27,6 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import com.android.internal.annotations.GuardedBy;
-
 import com.android.internal.app.ColorDisplayController;
 import java.util.Arrays;
 
@@ -46,6 +44,10 @@
      */
     public static final int LEVEL_COLOR_MATRIX_NIGHT_DISPLAY = 100;
     /**
+     * Color transform level used to adjust the color saturation of the display.
+     */
+    public static final int LEVEL_COLOR_MATRIX_SATURATION = 150;
+    /**
      * Color transform level used by A11y services to make the display monochromatic.
      */
     public static final int LEVEL_COLOR_MATRIX_GRAYSCALE = 200;
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 3374b30..c445f73 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -2576,9 +2576,9 @@
             // register for connectivity change events, this is equivalent to the deprecated way of
             // registering for CONNECTIVITY_ACTION broadcasts
             NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
-            networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-            networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
-            networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_BLUETOOTH);
+            networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+            networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
+            networkRequestBuilder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
             NetworkRequest networkRequest = networkRequestBuilder.build();
             mConnMgr.registerNetworkCallback(networkRequest, mNetworkConnectivityCallback);
 
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
index 050c1f4..b0afac2 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
@@ -79,6 +79,7 @@
     private final PlatformKeyManager mPlatformKeyManager;
     private final RecoverySnapshotStorage mRecoverySnapshotStorage;
     private final RecoverySnapshotListenersStorage mSnapshotListenersStorage;
+    private final TestOnlyInsecureCertificateHelper mTestOnlyInsecureCertificateHelper;
 
     public static KeySyncTask newInstance(
             Context context,
@@ -98,7 +99,8 @@
                 credentialType,
                 credential,
                 credentialUpdated,
-                PlatformKeyManager.getInstance(context, recoverableKeyStoreDb));
+                PlatformKeyManager.getInstance(context, recoverableKeyStoreDb),
+                new TestOnlyInsecureCertificateHelper());
     }
 
     /**
@@ -110,6 +112,7 @@
      * @param credential The credential, encoded as a {@link String}.
      * @param credentialUpdated signals weather credentials were updated.
      * @param platformKeyManager platform key manager
+     * @param TestOnlyInsecureCertificateHelper utility class used for end-to-end tests
      */
     @VisibleForTesting
     KeySyncTask(
@@ -120,7 +123,8 @@
             int credentialType,
             String credential,
             boolean credentialUpdated,
-            PlatformKeyManager platformKeyManager) {
+            PlatformKeyManager platformKeyManager,
+            TestOnlyInsecureCertificateHelper TestOnlyInsecureCertificateHelper) {
         mSnapshotListenersStorage = recoverySnapshotListenersStorage;
         mRecoverableKeyStoreDb = recoverableKeyStoreDb;
         mUserId = userId;
@@ -129,6 +133,7 @@
         mCredentialUpdated = credentialUpdated;
         mPlatformKeyManager = platformKeyManager;
         mRecoverySnapshotStorage = snapshotStorage;
+        mTestOnlyInsecureCertificateHelper = TestOnlyInsecureCertificateHelper;
     }
 
     @Override
@@ -189,8 +194,9 @@
         PublicKey publicKey;
         String rootCertAlias =
                 mRecoverableKeyStoreDb.getActiveRootOfTrust(mUserId, recoveryAgentUid);
+        rootCertAlias = mTestOnlyInsecureCertificateHelper
+                .getDefaultCertificateAliasIfEmpty(rootCertAlias);
 
-        rootCertAlias = replaceEmptyValueWithSecureDefault(rootCertAlias);
         CertPath certPath = mRecoverableKeyStoreDb.getRecoveryServiceCertPath(mUserId,
                 recoveryAgentUid, rootCertAlias);
         if (certPath != null) {
@@ -212,12 +218,18 @@
             return;
         }
 
-        // The only place in this class which uses credential value
-        if (!TrustedRootCertificates.GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS.equals(
-                rootCertAlias)) {
-            // TODO: allow only whitelisted LSKF usage
-            Log.w(TAG, "Untrusted root certificate is used by recovery agent "
+        if (mTestOnlyInsecureCertificateHelper.isTestOnlyCertificate(rootCertAlias)) {
+            Log.w(TAG, "Insecure root certificate is used by recovery agent "
                     + recoveryAgentUid);
+            if (mTestOnlyInsecureCertificateHelper.doesCredentailSupportInsecureMode(
+                    mCredentialType, mCredential)) {
+                Log.w(TAG, "Whitelisted credential is used to generate snapshot by "
+                        + "recovery agent "+ recoveryAgentUid);
+            } else {
+                Log.w(TAG, "Non whitelisted credential is used to generate recovery snapshot by "
+                        + recoveryAgentUid + " - ignore attempt.");
+                return; // User secret will not be used.
+            }
         }
 
         byte[] salt = generateSalt();
@@ -239,8 +251,10 @@
             return;
         }
 
-        // TODO: filter raw keys based on the root of trust.
-        // It is the only place in the class where raw key material is used.
+        // Only include insecure key material for test
+        if (mTestOnlyInsecureCertificateHelper.isTestOnlyCertificate(rootCertAlias)) {
+            rawKeys = mTestOnlyInsecureCertificateHelper.keepOnlyWhitelistedInsecureKeys(rawKeys);
+        }
         SecretKey recoveryKey;
         try {
             recoveryKey = generateRecoveryKey();
@@ -467,14 +481,4 @@
         }
         return keyEntries;
     }
-
-    private @NonNull String replaceEmptyValueWithSecureDefault(
-            @Nullable String rootCertificateAlias) {
-        if (rootCertificateAlias == null || rootCertificateAlias.isEmpty()) {
-            Log.e(TAG, "rootCertificateAlias is null or empty");
-            // Use the default Google Key Vault Service CA certificate if the alias is not provided
-            rootCertificateAlias = TrustedRootCertificates.GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS;
-        }
-        return rootCertificateAlias;
-    }
 }
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index 77d7c3c..1dab592 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -38,7 +38,6 @@
 import android.security.keystore.recovery.KeyChainSnapshot;
 import android.security.keystore.recovery.RecoveryCertPath;
 import android.security.keystore.recovery.RecoveryController;
-import android.security.keystore.recovery.TrustedRootCertificates;
 import android.security.keystore.recovery.WrappedApplicationKey;
 import android.security.KeyStore;
 import android.util.ArrayMap;
@@ -100,6 +99,7 @@
     private final RecoverySnapshotStorage mSnapshotStorage;
     private final PlatformKeyManager mPlatformKeyManager;
     private final ApplicationKeyStorage mApplicationKeyStorage;
+    private final TestOnlyInsecureCertificateHelper mTestCertHelper;
 
     /**
      * Returns a new or existing instance.
@@ -130,7 +130,8 @@
                     RecoverySnapshotStorage.newInstance(),
                     new RecoverySnapshotListenersStorage(),
                     platformKeyManager,
-                    applicationKeyStorage);
+                    applicationKeyStorage,
+                    new TestOnlyInsecureCertificateHelper());
         }
         return mInstance;
     }
@@ -144,7 +145,8 @@
             RecoverySnapshotStorage snapshotStorage,
             RecoverySnapshotListenersStorage listenersStorage,
             PlatformKeyManager platformKeyManager,
-            ApplicationKeyStorage applicationKeyStorage) {
+            ApplicationKeyStorage applicationKeyStorage,
+            TestOnlyInsecureCertificateHelper TestOnlyInsecureCertificateHelper) {
         mContext = context;
         mDatabase = recoverableKeyStoreDb;
         mRecoverySessionStorage = recoverySessionStorage;
@@ -153,6 +155,7 @@
         mSnapshotStorage = snapshotStorage;
         mPlatformKeyManager = platformKeyManager;
         mApplicationKeyStorage = applicationKeyStorage;
+        mTestCertHelper = TestOnlyInsecureCertificateHelper;
 
         try {
             mRecoverableKeyGenerator = RecoverableKeyGenerator.newInstance(mDatabase);
@@ -171,7 +174,8 @@
         checkRecoverKeyStorePermission();
         int userId = UserHandle.getCallingUserId();
         int uid = Binder.getCallingUid();
-        rootCertificateAlias = replaceEmptyValueWithSecureDefault(rootCertificateAlias);
+        rootCertificateAlias
+                = mTestCertHelper.getDefaultCertificateAliasIfEmpty(rootCertificateAlias);
 
         // Always set active alias to the argument of the last call to initRecoveryService method,
         // even if cert file is incorrect.
@@ -216,7 +220,8 @@
 
         // Randomly choose and validate an endpoint certificate from the list
         CertPath certPath;
-        X509Certificate rootCert = getRootCertificate(rootCertificateAlias);
+        X509Certificate rootCert =
+                mTestCertHelper.getRootCertificate(rootCertificateAlias);
         try {
             Log.d(TAG, "Getting and validating a random endpoint certificate");
             certPath = certXml.getRandomEndpointCert(rootCert);
@@ -265,7 +270,8 @@
             @NonNull byte[] recoveryServiceSigFile)
             throws RemoteException {
         checkRecoverKeyStorePermission();
-        rootCertificateAlias = replaceEmptyValueWithSecureDefault(rootCertificateAlias);
+        rootCertificateAlias =
+                mTestCertHelper.getDefaultCertificateAliasIfEmpty(rootCertificateAlias);
         Preconditions.checkNotNull(recoveryServiceCertFile, "recoveryServiceCertFile is null");
         Preconditions.checkNotNull(recoveryServiceSigFile, "recoveryServiceSigFile is null");
 
@@ -279,7 +285,8 @@
                     ERROR_BAD_CERTIFICATE_FORMAT, "Failed to parse the sig file.");
         }
 
-        X509Certificate rootCert = getRootCertificate(rootCertificateAlias);
+        X509Certificate rootCert =
+                mTestCertHelper.getRootCertificate(rootCertificateAlias);
         try {
             sigXml.verifyFileSignature(rootCert, recoveryServiceCertFile);
         } catch (CertValidationException e) {
@@ -519,7 +526,8 @@
             @NonNull List<KeyChainProtectionParams> secrets)
             throws RemoteException {
         checkRecoverKeyStorePermission();
-        rootCertificateAlias = replaceEmptyValueWithSecureDefault(rootCertificateAlias);
+        rootCertificateAlias =
+                mTestCertHelper.getDefaultCertificateAliasIfEmpty(rootCertificateAlias);
         Preconditions.checkNotNull(sessionId, "invalid session");
         Preconditions.checkNotNull(verifierCertPath, "verifierCertPath is null");
         Preconditions.checkNotNull(vaultParams, "vaultParams is null");
@@ -534,7 +542,8 @@
         }
 
         try {
-            CertUtils.validateCertPath(getRootCertificate(rootCertificateAlias), certPath);
+            CertUtils.validateCertPath(
+                    mTestCertHelper.getRootCertificate(rootCertificateAlias), certPath);
         } catch (CertValidationException e) {
             Log.e(TAG, "Failed to validate the given cert path", e);
             throw new ServiceSpecificException(ERROR_INVALID_CERTIFICATE, e.getMessage());
@@ -960,27 +969,6 @@
         }
     }
 
-    private X509Certificate getRootCertificate(String rootCertificateAlias) throws RemoteException {
-        rootCertificateAlias = replaceEmptyValueWithSecureDefault(rootCertificateAlias);
-        X509Certificate rootCertificate =
-                TrustedRootCertificates.getRootCertificate(rootCertificateAlias);
-        if (rootCertificate == null) {
-            throw new ServiceSpecificException(
-                    ERROR_INVALID_CERTIFICATE, "The provided root certificate alias is invalid");
-        }
-        return rootCertificate;
-    }
-
-    private @NonNull String replaceEmptyValueWithSecureDefault(
-            @Nullable String rootCertificateAlias) {
-        if (rootCertificateAlias == null || rootCertificateAlias.isEmpty()) {
-            Log.e(TAG, "rootCertificateAlias is null or empty");
-            // Use the default Google Key Vault Service CA certificate if the alias is not provided
-            rootCertificateAlias = TrustedRootCertificates.GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS;
-        }
-        return rootCertificateAlias;
-    }
-
     private void checkRecoverKeyStorePermission() {
         mContext.enforceCallingOrSelfPermission(
                 Manifest.permission.RECOVER_KEYSTORE,
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java
new file mode 100644
index 0000000..490f733
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.locksettings.recoverablekeystore;
+
+import static android.security.keystore.recovery.RecoveryController.ERROR_INVALID_CERTIFICATE;
+
+import com.android.internal.widget.LockPatternUtils;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+import android.security.keystore.recovery.TrustedRootCertificates;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.security.cert.X509Certificate;
+import java.util.Map;
+import javax.crypto.SecretKey;
+
+/**
+ * The class provides helper methods to support end-to-end test with insecure certificate.
+ */
+public class TestOnlyInsecureCertificateHelper {
+    private static final String TAG = "TestCertHelper";
+
+    /**
+     * Constructor for the helper class.
+     */
+    public TestOnlyInsecureCertificateHelper() {
+    }
+
+    /**
+     * Returns a root certificate installed in the system for given alias.
+     * Returns default secure certificate if alias is empty or null.
+     * Can return insecure certificate for its alias.
+     */
+    public @NonNull X509Certificate
+            getRootCertificate(String rootCertificateAlias) throws RemoteException {
+        rootCertificateAlias = getDefaultCertificateAliasIfEmpty(rootCertificateAlias);
+        if (isTestOnlyCertificate(rootCertificateAlias)) {
+            return TrustedRootCertificates.getTestOnlyInsecureCertificate();
+        }
+
+        X509Certificate rootCertificate =
+                TrustedRootCertificates.getRootCertificate(rootCertificateAlias);
+        if (rootCertificate == null) {
+            throw new ServiceSpecificException(
+                    ERROR_INVALID_CERTIFICATE, "The provided root certificate alias is invalid");
+        }
+        return rootCertificate;
+    }
+
+    public @NonNull String getDefaultCertificateAliasIfEmpty(
+            @Nullable String rootCertificateAlias) {
+        if (rootCertificateAlias == null || rootCertificateAlias.isEmpty()) {
+            Log.e(TAG, "rootCertificateAlias is null or empty - use secure default value");
+            // Use the default Google Key Vault Service CA certificate if the alias is not provided
+            rootCertificateAlias = TrustedRootCertificates.GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS;
+        }
+        return rootCertificateAlias;
+    }
+
+    public boolean isTestOnlyCertificate(String rootCertificateAlias) {
+        return TrustedRootCertificates.TEST_ONLY_INSECURE_CERTIFICATE_ALIAS
+                .equals(rootCertificateAlias);
+    }
+
+    public boolean doesCredentailSupportInsecureMode(int credentialType, String credential) {
+        return (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD)
+            && (credential != null)
+            && credential.startsWith(TrustedRootCertificates.INSECURE_PASSWORD_PREFIX);
+    }
+
+    public Map<String, SecretKey> keepOnlyWhitelistedInsecureKeys(Map<String, SecretKey> rawKeys) {
+        if (rawKeys == null) {
+            return null;
+        }
+        Map<String, SecretKey> filteredKeys = new HashMap<>();
+        for (Map.Entry<String, SecretKey> entry : rawKeys.entrySet()) {
+            String alias = entry.getKey();
+            if (alias != null
+                    && alias.startsWith(TrustedRootCertificates.INSECURE_KEY_ALIAS_PREFIX)) {
+                filteredKeys.put(entry.getKey(), entry.getValue());
+                Log.d(TAG, "adding key with insecure alias " + alias + " to the recovery snapshot");
+            }
+        }
+        return filteredKeys;
+    }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 31b0461..f31ca0a 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -182,6 +182,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.internal.util.ArrayUtils;
@@ -898,6 +899,8 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
+                // update system notification channels
+                SystemNotificationChannels.createAll(context);
                 mZenModeHelper.updateDefaultZenRules();
                 mRankingHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
             }
diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
index c0c66b2..6cf8f86 100644
--- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
+++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
@@ -468,12 +468,14 @@
         private final LinkedList<String> mPendingLookups;
         private final Context mContext;
 
+        // Amount of time to wait for a result from the contacts db before rechecking affinity.
+        private static final long LOOKUP_TIME = 1000;
         private float mContactAffinity = NONE;
         private NotificationRecord mRecord;
 
         private PeopleRankingReconsideration(Context context, String key,
                 LinkedList<String> pendingLookups) {
-            super(key);
+            super(key, LOOKUP_TIME);
             mContext = context;
             mPendingLookups = pendingLookups;
         }
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 61c6be7..9807342 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -449,13 +449,15 @@
             pw.increaseIndent();
 
             for (String isa : dexCodeInstructionSets) {
-                String status = null;
                 try {
-                    status = DexFile.getDexFileStatus(path, isa);
+                    String[] status = DexFile.getDexFileOptimizationStatus(path, isa);
+                    String compilationStatus = status[0];
+                    String compilationReason = status[1];
+                    pw.println(isa + ": [status=" + compilationStatus
+                            +"] reason=[" + compilationReason + "]");
                 } catch (IOException ioe) {
-                     status = "[Exception]: " + ioe.getMessage();
+                    pw.println(isa + ": [Exception]: " + ioe.getMessage());
                 }
-                pw.println(isa + ": " + status);
             }
 
             if (useInfo.isUsedByOtherApps(path)) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e08ec556..7b77c96 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -808,7 +808,7 @@
         }
 
         final String[] getStaticOverlayPaths(List<PackageParser.Package> overlayPackages,
-                String targetPath, Object installLock) {
+                String targetPath) {
             if (overlayPackages == null || overlayPackages.isEmpty()) {
                 return null;
             }
@@ -828,20 +828,9 @@
                     //
                     // OverlayManagerService will update each of them with a correct gid from its
                     // target package app id.
-                    if (installLock != null) {
-                        synchronized (installLock) {
-                            mInstaller.idmap(targetPath, overlayPackage.baseCodePath,
-                                    UserHandle.getSharedAppGid(
-                                            UserHandle.getUserGid(UserHandle.USER_SYSTEM)));
-                        }
-                    } else {
-                        // We can call mInstaller without holding mInstallLock because mInstallLock
-                        // is held before running parallel parsing.
-                        // Moreover holding mInstallLock on each parsing thread causes dead-lock.
-                        mInstaller.idmap(targetPath, overlayPackage.baseCodePath,
-                                UserHandle.getSharedAppGid(
-                                        UserHandle.getUserGid(UserHandle.USER_SYSTEM)));
-                    }
+                    mInstaller.idmap(targetPath, overlayPackage.baseCodePath,
+                            UserHandle.getSharedAppGid(
+                                    UserHandle.getUserGid(UserHandle.USER_SYSTEM)));
                     if (overlayPathList == null) {
                         overlayPathList = new ArrayList<String>();
                     }
@@ -856,13 +845,15 @@
 
         String[] getStaticOverlayPaths(String targetPackageName, String targetPath) {
             List<PackageParser.Package> overlayPackages;
-            synchronized (mPackages) {
-                overlayPackages = getStaticOverlayPackages(
-                        mPackages.values(), targetPackageName);
+            synchronized (mInstallLock) {
+                synchronized (mPackages) {
+                    overlayPackages = getStaticOverlayPackages(
+                            mPackages.values(), targetPackageName);
+                }
+                // It is safe to keep overlayPackages without holding mPackages because static overlay
+                // packages can't be uninstalled or disabled.
+                return getStaticOverlayPaths(overlayPackages, targetPath);
             }
-            // It is safe to keep overlayPackages without holding mPackages because static overlay
-            // packages can't be uninstalled or disabled.
-            return getStaticOverlayPaths(overlayPackages, targetPath, mInstallLock);
         }
 
         @Override public final String[] getOverlayApks(String targetPackageName) {
@@ -895,11 +886,13 @@
         synchronized String[] getStaticOverlayPaths(String targetPackageName, String targetPath) {
             // We can trust mOverlayPackages without holding mPackages because package uninstall
             // can't happen while running parallel parsing.
-            // Moreover holding mPackages on each parsing thread causes dead-lock.
+            // And we can call mInstaller inside getStaticOverlayPaths without holding mInstallLock
+            // because mInstallLock is held before running parallel parsing.
+            // Moreover holding mPackages or mInstallLock on each parsing thread causes dead-lock.
             return mOverlayPackages == null ? null :
                     getStaticOverlayPaths(
                             getStaticOverlayPackages(mOverlayPackages, targetPackageName),
-                            targetPath, null);
+                            targetPath);
         }
     }
 
@@ -16810,12 +16803,6 @@
                 if (userId != UserHandle.USER_ALL) {
                     ps.setInstalled(true, userId);
                     ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName);
-                } else {
-                    for (int currentUserId : sUserManager.getUserIds()) {
-                        ps.setInstalled(true, currentUserId);
-                        ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, currentUserId,
-                                installerPackageName);
-                    }
                 }
 
                 // When replacing an existing package, preserve the original install reason for all
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index 941cd44..e56caf8 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -19,6 +19,8 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.security.IKeystoreService;
 import android.util.Slog;
 
 import com.android.internal.policy.IKeyguardService;
@@ -51,11 +53,16 @@
     private final LockPatternUtils mLockPatternUtils;
     private final StateCallback mCallback;
 
+    IKeystoreService mKeystoreService;
+
     public KeyguardStateMonitor(Context context, IKeyguardService service, StateCallback callback) {
         mLockPatternUtils = new LockPatternUtils(context);
         mCurrentUserId = ActivityManager.getCurrentUser();
         mCallback = callback;
 
+        mKeystoreService = IKeystoreService.Stub.asInterface(ServiceManager
+                .getService("android.security.keystore"));
+
         try {
             service.addStateMonitorCallback(this);
         } catch (RemoteException e) {
@@ -86,6 +93,12 @@
     @Override // Binder interface
     public void onShowingStateChanged(boolean showing) {
         mIsShowing = showing;
+
+        try {
+            mKeystoreService.onKeyguardVisibilityChanged(showing, mCurrentUserId);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Error informing keystore of screen lock", e);
+        }
     }
 
     @Override // Binder interface
@@ -130,4 +143,4 @@
         pw.println(prefix + "mTrusted=" + mTrusted);
         pw.println(prefix + "mCurrentUserId=" + mCurrentUserId);
     }
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/wm/StrictModeFlash.java b/services/core/java/com/android/server/wm/StrictModeFlash.java
index f51a6a9..e97b366 100644
--- a/services/core/java/com/android/server/wm/StrictModeFlash.java
+++ b/services/core/java/com/android/server/wm/StrictModeFlash.java
@@ -79,17 +79,25 @@
         }
 
         // Top
-        c.clipRect(new Rect(0, 0, dw, mThickness), Region.Op.REPLACE);
+        c.save();
+        c.clipRect(new Rect(0, 0, dw, mThickness));
         c.drawColor(Color.RED);
+        c.restore();
         // Left
-        c.clipRect(new Rect(0, 0, mThickness, dh), Region.Op.REPLACE);
+        c.save();
+        c.clipRect(new Rect(0, 0, mThickness, dh));
         c.drawColor(Color.RED);
+        c.restore();
         // Right
-        c.clipRect(new Rect(dw - mThickness, 0, dw, dh), Region.Op.REPLACE);
+        c.save();
+        c.clipRect(new Rect(dw - mThickness, 0, dw, dh));
         c.drawColor(Color.RED);
+        c.restore();
         // Bottom
-        c.clipRect(new Rect(0, dh - mThickness, dw, dh), Region.Op.REPLACE);
+        c.save();
+        c.clipRect(new Rect(0, dh - mThickness, dw, dh));
         c.drawColor(Color.RED);
+        c.restore();
 
         mSurface.unlockCanvasAndPost(c);
     }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 71c2ea1..1c9782f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -78,23 +78,6 @@
         return false;
     }
 
-    @Override
-    public boolean setPasswordBlacklist(ComponentName who, String name, List<String> blacklist,
-            boolean parent) {
-        return false;
-    }
-
-    @Override
-    public String getPasswordBlacklistName(ComponentName who, @UserIdInt int userId,
-            boolean parent) {
-        return null;
-    }
-
-    @Override
-    public boolean isPasswordBlacklisted(@UserIdInt int userId, String password) {
-        return false;
-    }
-
     public boolean isUsingUnifiedPassword(ComponentName who) {
         return true;
     }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 02cd3b6..90e8a9c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -820,7 +820,6 @@
         private static final String TAG_PASSWORD_HISTORY_LENGTH = "password-history-length";
         private static final String TAG_MIN_PASSWORD_LENGTH = "min-password-length";
         private static final String ATTR_VALUE = "value";
-        private static final String TAG_PASSWORD_BLACKLIST = "password-blacklist";
         private static final String TAG_PASSWORD_QUALITY = "password-quality";
         private static final String TAG_POLICIES = "policies";
         private static final String TAG_CROSS_PROFILE_WIDGET_PROVIDERS =
@@ -961,9 +960,6 @@
         // Default title of confirm credentials screen
         String organizationName = null;
 
-        // The blacklist data is stored in a file whose name is stored in the XML
-        String passwordBlacklistFile = null;
-
         // The component name of the backup transport which has to be used if backups are mandatory
         // or null if backups are not mandatory.
         ComponentName mandatoryBackupTransport = null;
@@ -1053,11 +1049,6 @@
                     out.endTag(null, TAG_MIN_PASSWORD_NONLETTER);
                 }
             }
-            if (passwordBlacklistFile != null) {
-                out.startTag(null, TAG_PASSWORD_BLACKLIST);
-                out.attribute(null, ATTR_VALUE, passwordBlacklistFile);
-                out.endTag(null, TAG_PASSWORD_BLACKLIST);
-            }
             if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) {
                 out.startTag(null, TAG_MAX_TIME_TO_UNLOCK);
                 out.attribute(null, ATTR_VALUE, Long.toString(maximumTimeToUnlock));
@@ -1313,8 +1304,6 @@
                 } else if (TAG_MIN_PASSWORD_NONLETTER.equals(tag)) {
                     minimumPasswordMetrics.nonLetter = Integer.parseInt(
                             parser.getAttributeValue(null, ATTR_VALUE));
-                } else if (TAG_PASSWORD_BLACKLIST.equals(tag)) {
-                    passwordBlacklistFile = parser.getAttributeValue(null, ATTR_VALUE);
                 }else if (TAG_MAX_TIME_TO_UNLOCK.equals(tag)) {
                     maximumTimeToUnlock = Long.parseLong(
                             parser.getAttributeValue(null, ATTR_VALUE));
@@ -1589,8 +1578,6 @@
                     pw.println(minimumPasswordMetrics.symbols);
             pw.print(prefix); pw.print("minimumPasswordNonLetter=");
                     pw.println(minimumPasswordMetrics.nonLetter);
-            pw.print(prefix); pw.print("passwordBlacklist=");
-                    pw.println(passwordBlacklistFile != null);
             pw.print(prefix); pw.print("maximumTimeToUnlock=");
                     pw.println(maximumTimeToUnlock);
             pw.print(prefix); pw.print("strongAuthUnlockTimeout=");
@@ -1857,10 +1844,6 @@
             return new LockPatternUtils(mContext);
         }
 
-        PasswordBlacklist newPasswordBlacklist(File file) {
-            return new PasswordBlacklist(file);
-        }
-
         boolean storageManagerIsFileBasedEncryptionEnabled() {
             return StorageManager.isFileEncryptedNativeOnly();
         }
@@ -2028,8 +2011,9 @@
             Settings.Global.putString(mContext.getContentResolver(), name, value);
         }
 
-        void settingsSystemPutString(String name, String value) {
-            Settings.System.putString(mContext.getContentResolver(), name, value);
+        void settingsSystemPutStringForUser(String name, String value, int userId) {
+          Settings.System.putStringForUser(
+              mContext.getContentResolver(), name, value, userId);
         }
 
         void securityLogSetLoggingEnabledProperty(boolean enabled) {
@@ -4412,136 +4396,6 @@
         }
     }
 
-    /* @return the password blacklist set by the admin or {@code null} if none. */
-    PasswordBlacklist getAdminPasswordBlacklistLocked(@NonNull ActiveAdmin admin) {
-        final int userId = UserHandle.getUserId(admin.getUid());
-        return admin.passwordBlacklistFile == null ? null : new PasswordBlacklist(
-                new File(getPolicyFileDirectory(userId), admin.passwordBlacklistFile));
-    }
-
-    private static final String PASSWORD_BLACKLIST_FILE_PREFIX = "password-blacklist-";
-    private static final String PASSWORD_BLACKLIST_FILE_SUFFIX = "";
-
-    @Override
-    public boolean setPasswordBlacklist(ComponentName who, String name, List<String> blacklist,
-            boolean parent) {
-        if (!mHasFeature) {
-            return false;
-        }
-        Preconditions.checkNotNull(who, "who is null");
-
-        synchronized (this) {
-            final ActiveAdmin admin = getActiveAdminForCallerLocked(
-                    who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, parent);
-            final int userId = mInjector.userHandleGetCallingUserId();
-            PasswordBlacklist adminBlacklist = getAdminPasswordBlacklistLocked(admin);
-
-            if (blacklist == null || blacklist.isEmpty()) {
-                // Remove the adminBlacklist
-                admin.passwordBlacklistFile = null;
-                saveSettingsLocked(userId);
-                if (adminBlacklist != null) {
-                    adminBlacklist.delete();
-                }
-                return true;
-            }
-
-            // Validate server side
-            Preconditions.checkNotNull(name, "name is null");
-            DevicePolicyManager.enforcePasswordBlacklistSize(blacklist);
-
-            // Blacklist is case insensitive so normalize to lower case
-            final int blacklistSize = blacklist.size();
-            for (int i = 0; i < blacklistSize; ++i) {
-                blacklist.set(i, blacklist.get(i).toLowerCase());
-            }
-
-            final boolean isNewBlacklist = adminBlacklist == null;
-            if (isNewBlacklist) {
-                // Create a new file for the blacklist. There could be multiple admins, each setting
-                // different blacklists, to restrict a user's credential, for example a managed
-                // profile can impose restrictions on its parent while the parent is already
-                // restricted by its own admin. A deterministic naming scheme would be fragile if
-                // new types of admin are introduced so we generate and save the file name instead.
-                // This isn't a temporary file but it reuses the name generation logic
-                final File file;
-                try {
-                    file = File.createTempFile(PASSWORD_BLACKLIST_FILE_PREFIX,
-                            PASSWORD_BLACKLIST_FILE_SUFFIX, getPolicyFileDirectory(userId));
-                } catch (IOException e) {
-                    Slog.e(LOG_TAG, "Failed to make a file for the blacklist", e);
-                    return false;
-                }
-                adminBlacklist = mInjector.newPasswordBlacklist(file);
-            }
-
-            if (adminBlacklist.savePasswordBlacklist(name, blacklist)) {
-                if (isNewBlacklist) {
-                    // The blacklist was saved so point the admin to the file
-                    admin.passwordBlacklistFile = adminBlacklist.getFile().getName();
-                    saveSettingsLocked(userId);
-                }
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    @Override
-    public String getPasswordBlacklistName(ComponentName who, @UserIdInt int userId,
-            boolean parent) {
-        if (!mHasFeature) {
-            return null;
-        }
-        Preconditions.checkNotNull(who, "who is null");
-        enforceFullCrossUsersPermission(userId);
-        synchronized (this) {
-            final ActiveAdmin admin = getActiveAdminForCallerLocked(
-                    who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, parent);
-            final PasswordBlacklist blacklist = getAdminPasswordBlacklistLocked(admin);
-            if (blacklist == null) {
-                return null;
-            }
-            return blacklist.getName();
-        }
-    }
-
-    @Override
-    public boolean isPasswordBlacklisted(@UserIdInt int userId, String password) {
-        if (!mHasFeature) {
-            return false;
-        }
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.TEST_BLACKLISTED_PASSWORD, null);
-        return isPasswordBlacklistedInternal(userId, password);
-    }
-
-    private boolean isPasswordBlacklistedInternal(@UserIdInt int userId, String password) {
-        Preconditions.checkNotNull(password, "Password is null");
-        enforceFullCrossUsersPermission(userId);
-
-        // Normalize to lower case for case insensitive blacklist match
-        final String lowerCasePassword = password.toLowerCase();
-
-        synchronized (this) {
-            final List<ActiveAdmin> admins =
-                    getActiveAdminsForLockscreenPoliciesLocked(userId, /* parent */ false);
-            final int N = admins.size();
-            for (int i = 0; i < N; i++) {
-                final PasswordBlacklist blacklist
-                        = getAdminPasswordBlacklistLocked(admins.get(i));
-                if (blacklist != null) {
-                    if (blacklist.isPasswordBlacklisted(lowerCasePassword)) {
-                        return true;
-                    }
-                }
-            }
-        }
-
-        return false;
-    }
-
     @Override
     public boolean isActivePasswordSufficient(int userHandle, boolean parent) {
         if (!mHasFeature) {
@@ -4937,11 +4791,6 @@
                     return false;
                 }
             }
-
-            if (isPasswordBlacklistedInternal(userHandle, password)) {
-                Slog.w(LOG_TAG, "resetPassword: the password is blacklisted");
-                return false;
-            }
         }
 
         DevicePolicyData policy = getUserData(userHandle);
@@ -10049,15 +9898,17 @@
         Preconditions.checkStringNotEmpty(setting, "String setting is null or empty");
 
         synchronized (this) {
-            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             if (!SYSTEM_SETTINGS_WHITELIST.contains(setting)) {
                 throw new SecurityException(String.format(
                         "Permission denial: device owners cannot update %1$s", setting));
             }
 
-            mInjector.binderWithCleanCallingIdentity(() -> mInjector.settingsSystemPutString(
-                    setting, value));
+            final int callingUserId = mInjector.userHandleGetCallingUserId();
+
+            mInjector.binderWithCleanCallingIdentity(() ->
+                mInjector.settingsSystemPutStringForUser(setting, value, callingUserId));
         }
     }
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PasswordBlacklist.java b/services/devicepolicy/java/com/android/server/devicepolicy/PasswordBlacklist.java
deleted file mode 100644
index a17a107..0000000
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PasswordBlacklist.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.devicepolicy;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.util.AtomicFile;
-import android.util.Slog;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.List;
-
-/**
- * Manages the blacklisted passwords.
- *
- * This caller must ensure synchronized access.
- */
-public class PasswordBlacklist {
-    private static final String TAG = "PasswordBlacklist";
-
-    private final AtomicFile mFile;
-
-    /**
-     * Create an object to manage the password blacklist.
-     *
-     * This is a lightweight operation to prepare variables but not perform any IO.
-     */
-    public PasswordBlacklist(File file) {
-        mFile = new AtomicFile(file, "device-policy");
-    }
-
-    /**
-     * Atomically replace the blacklist.
-     *
-     * Pass {@code null} for an empty list.
-     */
-    public boolean savePasswordBlacklist(@NonNull String name, @NonNull List<String> blacklist) {
-        FileOutputStream fos = null;
-        try {
-            fos = mFile.startWrite();
-            final DataOutputStream out = buildStreamForWriting(fos);
-            final Header header = new Header(Header.VERSION_1, name, blacklist.size());
-            header.write(out);
-            final int blacklistSize = blacklist.size();
-            for (int i = 0; i < blacklistSize; ++i) {
-                out.writeUTF(blacklist.get(i));
-            }
-            out.flush();
-            mFile.finishWrite(fos);
-            return true;
-        } catch (IOException e) {
-            mFile.failWrite(fos);
-            return false;
-        }
-    }
-
-    /** @return the name of the blacklist or {@code null} if none set. */
-    public String getName() {
-        try (DataInputStream in = openForReading()) {
-            return Header.read(in).mName;
-        } catch (IOException e) {
-            Slog.wtf(TAG, "Failed to read blacklist file", e);
-        }
-        return null;
-    }
-
-    /** @return the number of blacklisted passwords. */
-    public int getSize() {
-        final int blacklistSize;
-        try (DataInputStream in = openForReading()) {
-            return Header.read(in).mSize;
-        } catch (IOException e) {
-            Slog.wtf(TAG, "Failed to read blacklist file", e);
-        }
-        return 0;
-    }
-
-    /** @return whether the password matches an blacklisted item. */
-    public boolean isPasswordBlacklisted(@NonNull String password) {
-        final int blacklistSize;
-        try (DataInputStream in = openForReading()) {
-            final Header header = Header.read(in);
-            for (int i = 0; i < header.mSize; ++i) {
-                if (in.readUTF().equals(password)) {
-                    return true;
-                }
-            }
-        } catch (IOException e) {
-            Slog.wtf(TAG, "Failed to read blacklist file", e);
-            // Fail safe and block all passwords. Setting a new blacklist should resolve this
-            // problem which can be identified by examining the log.
-            return true;
-        }
-        return false;
-    }
-
-    /** Delete the blacklist completely from disk. */
-    public void delete() {
-        mFile.delete();
-    }
-
-    /** Get the file the blacklist is stored in. */
-    public File getFile() {
-        return mFile.getBaseFile();
-    }
-
-    private DataOutputStream buildStreamForWriting(FileOutputStream fos) {
-        return new DataOutputStream(new BufferedOutputStream(fos));
-    }
-
-    private DataInputStream openForReading() throws IOException {
-        return new DataInputStream(new BufferedInputStream(mFile.openRead()));
-    }
-
-    /**
-     * Helper to read and write the header of the blacklist file.
-     */
-    private static class Header {
-        static final int VERSION_1 = 1;
-
-        final int mVersion; // File format version
-        final String mName;
-        final int mSize;
-
-        Header(int version, String name, int size) {
-            mVersion = version;
-            mName = name;
-            mSize = size;
-        }
-
-        void write(DataOutputStream out) throws IOException {
-            out.writeInt(mVersion);
-            out.writeUTF(mName);
-            out.writeInt(mSize);
-        }
-
-        static Header read(DataInputStream in) throws IOException {
-            final int version = in.readInt();
-            final String name = in.readUTF();
-            final int size = in.readInt();
-            return new Header(version, name, size);
-        }
-    }
-}
diff --git a/services/net/java/android/net/apf/ApfGenerator.java b/services/net/java/android/net/apf/ApfGenerator.java
index d41fbce..ca8f727 100644
--- a/services/net/java/android/net/apf/ApfGenerator.java
+++ b/services/net/java/android/net/apf/ApfGenerator.java
@@ -367,7 +367,7 @@
      */
     public boolean setApfVersion(int version) {
         // This version number syncs up with APF_VERSION in hardware/google/apf/apf_interpreter.h
-        return version == 2;
+        return version >= 2;
     }
 
     private void addInstruction(Instruction instruction) {
diff --git a/services/net/java/android/net/util/InterfaceSet.java b/services/net/java/android/net/util/InterfaceSet.java
new file mode 100644
index 0000000..9f26fa1
--- /dev/null
+++ b/services/net/java/android/net/util/InterfaceSet.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.util;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.StringJoiner;
+
+
+/**
+ * @hide
+ */
+public class InterfaceSet {
+    public final Set<String> ifnames;
+
+    public InterfaceSet(String... names) {
+        final Set<String> nameSet = new HashSet<>();
+        for (String name : names) {
+            if (name != null) nameSet.add(name);
+        }
+        ifnames = Collections.unmodifiableSet(nameSet);
+    }
+
+    @Override
+    public String toString() {
+        final StringJoiner sj = new StringJoiner(",", "[", "]");
+        for (String ifname : ifnames) sj.add(ifname);
+        return sj.toString();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        return obj != null
+                && obj instanceof InterfaceSet
+                && ifnames.equals(((InterfaceSet)obj).ifnames);
+    }
+}
diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml
index 082827c..0ec16b5 100644
--- a/services/tests/servicestests/AndroidTest.xml
+++ b/services/tests/servicestests/AndroidTest.xml
@@ -14,7 +14,9 @@
      limitations under the License.
 -->
 <configuration description="Runs Frameworks Services Tests.">
-    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-instrumentation" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="FrameworksServicesTests.apk" />
         <option name="test-file-name" value="JobTestApp.apk" />
@@ -22,7 +24,6 @@
         <option name="test-file-name" value="SuspendTestApp.apk" />
     </target_preparer>
 
-    <option name="test-suite-tag" value="apct" />
     <option name="test-tag" value="FrameworksServicesTests" />
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.frameworks.servicestests" />
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
index 7c3ea4f..e37ed79 100644
--- a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
@@ -17,6 +17,7 @@
 package com.android.server.content;
 
 import android.accounts.Account;
+import android.content.ContentResolver;
 import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.test.AndroidTestCase;
@@ -60,7 +61,7 @@
                 "authority1",
                 b1,
                 false,
-                /*isAppStandbyExempted=*/ false);
+                ContentResolver.SYNC_EXEMPTION_NONE);
 
         // Same as op1 but different time infos
         SyncOperation op2 = new SyncOperation(account1, 0,
@@ -69,7 +70,7 @@
                 "authority1",
                 b1,
                 false,
-                /*isAppStandbyExempted=*/ false);
+                ContentResolver.SYNC_EXEMPTION_NONE);
 
         // Same as op1 but different authority
         SyncOperation op3 = new SyncOperation(account1, 0,
@@ -78,7 +79,7 @@
                 "authority2",
                 b1,
                 false,
-                /*isAppStandbyExempted=*/ false);
+                ContentResolver.SYNC_EXEMPTION_NONE);
 
         // Same as op1 but different account
         SyncOperation op4 = new SyncOperation(account2, 0,
@@ -87,7 +88,7 @@
                 "authority1",
                 b1,
                 false,
-                /*isAppStandbyExempted=*/ false);
+                ContentResolver.SYNC_EXEMPTION_NONE);
 
         // Same as op1 but different bundle
         SyncOperation op5 = new SyncOperation(account1, 0,
@@ -96,7 +97,7 @@
                 "authority1",
                 b2,
                 false,
-                /*isAppStandbyExempted=*/ false);
+                ContentResolver.SYNC_EXEMPTION_NONE);
 
         assertEquals(op1.key, op2.key);
         assertNotSame(op1.key, op3.key);
@@ -117,7 +118,7 @@
                 "authority1",
                 b1,
                 false,
-                /*isAppStandbyExempted=*/ false);
+                ContentResolver.SYNC_EXEMPTION_NONE);
 
         PersistableBundle pb = op1.toJobInfoExtras();
         SyncOperation op2 = SyncOperation.maybeCreateFromJobExtras(pb);
@@ -145,7 +146,7 @@
         Bundle extras = new Bundle();
         SyncOperation periodic = new SyncOperation(ep, 0, "package", 0, 0, extras, false, true,
                 SyncOperation.NO_JOB_ID, 60000, 10000,
-                /*isAppStandbyExempted=*/ false);
+                ContentResolver.SYNC_EXEMPTION_NONE);
         SyncOperation oneoff = periodic.createOneTimeSyncOperation();
         assertFalse("Conversion to oneoff sync failed.", oneoff.isPeriodic);
         assertEquals("Period not restored", periodic.periodMillis, oneoff.periodMillis);
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
deleted file mode 100644
index 7209c79..0000000
--- a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.content;
-
-import android.accounts.Account;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.os.Bundle;
-import android.test.AndroidTestCase;
-import android.test.RenamingDelegatingContext;
-import android.test.mock.MockContentResolver;
-import android.test.mock.MockContext;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
-
-import com.android.internal.os.AtomicFile;
-
-import java.io.File;
-import java.io.FileOutputStream;
-
-/**
- * Test for SyncStorageEngine.
- *
- * bit FrameworksServicesTests:com.android.server.content.SyncStorageEngineTest
- *
- * TODO Broken.  Fix it.  b/62485315
- */
-@Suppress
-public class SyncStorageEngineTest extends AndroidTestCase {
-
-    protected Account account1;
-    protected Account account2;
-    protected ComponentName syncService1;
-    protected String authority1 = "testprovider";
-    protected Bundle defaultBundle;
-    protected final int DEFAULT_USER = 0;
-
-    /* Some default poll frequencies. */
-    final long dayPoll = (60 * 60 * 24);
-    final long dayFuzz = 60;
-    final long thousandSecs = 1000;
-    final long thousandSecsFuzz = 100;
-
-    MockContentResolver mockResolver;
-    SyncStorageEngine engine;
-
-    private File getSyncDir() {
-        return new File(new File(getContext().getFilesDir(), "system"), "sync");
-    }
-
-    @Override
-    public void setUp() {
-        account1 = new Account("a@example.com", "example.type");
-        account2 = new Account("b@example.com", "example.type");
-        syncService1 = new ComponentName("com.example", "SyncService");
-        // Default bundle.
-        defaultBundle = new Bundle();
-        defaultBundle.putInt("int_key", 0);
-        defaultBundle.putString("string_key", "hello");
-        // Set up storage engine.
-        mockResolver = new MockContentResolver();
-        engine = SyncStorageEngine.newTestInstance(
-                new TestContext(mockResolver, getContext()));
-    }
-
-    /**
-     * Test that we handle the case of a history row being old enough to purge before the
-     * corresponding sync is finished. This can happen if the clock changes while we are syncing.
-     *
-     */
-    // TODO: this test causes AidlTest to fail. Omit for now
-    // @SmallTest
-    public void testPurgeActiveSync() throws Exception {
-        final Account account = new Account("a@example.com", "example.type");
-        final String authority = "testprovider";
-
-        MockContentResolver mockResolver = new MockContentResolver();
-
-        SyncStorageEngine engine = SyncStorageEngine.newTestInstance(
-                new TestContext(mockResolver, getContext()));
-        long time0 = 1000;
-        SyncOperation op = new SyncOperation(account, 0, 0, "foo",
-                SyncOperation.REASON_PERIODIC,
-                SyncStorageEngine.SOURCE_LOCAL,
-                authority,
-                Bundle.EMPTY, true,
-                /*isAppStandbyExempted=*/ false);
-        long historyId = engine.insertStartSyncEvent(op, time0);
-        long time1 = time0 + SyncStorageEngine.MILLIS_IN_4WEEKS * 2;
-        engine.stopSyncEvent(historyId, time1 - time0, "yay", 0, 0);
-    }
-
-    @LargeTest
-    public void testAuthorityPersistence() throws Exception {
-        final Account account1 = new Account("a@example.com", "example.type");
-        final Account account2 = new Account("b@example.com", "example.type.2");
-        final String authority1 = "testprovider1";
-        final String authority2 = "testprovider2";
-
-        engine.setMasterSyncAutomatically(false, 0);
-
-        engine.setIsSyncable(account1, 0, authority1, 1);
-        engine.setSyncAutomatically(account1, 0, authority1, true);
-
-        engine.setIsSyncable(account2, 0, authority1, 1);
-        engine.setSyncAutomatically(account2, 0, authority1, true);
-
-        engine.setIsSyncable(account1, 0, authority2, 1);
-        engine.setSyncAutomatically(account1, 0, authority2, false);
-
-        engine.setIsSyncable(account2, 0, authority2, 0);
-        engine.setSyncAutomatically(account2, 0, authority2, true);
-
-        engine.writeAllState();
-        engine.clearAndReadState();
-
-        assertEquals(true, engine.getSyncAutomatically(account1, 0, authority1));
-        assertEquals(true, engine.getSyncAutomatically(account2, 0, authority1));
-        assertEquals(false, engine.getSyncAutomatically(account1, 0, authority2));
-        assertEquals(true, engine.getSyncAutomatically(account2, 0, authority2));
-
-        assertEquals(1, engine.getIsSyncable(account1, 0, authority1));
-        assertEquals(1, engine.getIsSyncable(account2, 0, authority1));
-        assertEquals(1, engine.getIsSyncable(account1, 0, authority2));
-        assertEquals(0, engine.getIsSyncable(account2, 0, authority2));
-    }
-
-    @MediumTest
-    public void testListenForTicklesParsing() throws Exception {
-        byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
-                + "<accounts>\n"
-                + "<listenForTickles user=\"0\" enabled=\"false\" />"
-                + "<listenForTickles user=\"1\" enabled=\"true\" />"
-                + "<authority id=\"0\" user=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\" />\n"
-                + "<authority id=\"1\" user=\"1\" account=\"account1\" type=\"type1\" authority=\"auth1\" />\n"
-                + "</accounts>\n").getBytes();
-
-        MockContentResolver mockResolver = new MockContentResolver();
-        final TestContext testContext = new TestContext(mockResolver, getContext());
-
-        File syncDir = getSyncDir();
-        syncDir.mkdirs();
-        AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
-        FileOutputStream fos = accountInfoFile.startWrite();
-        fos.write(accountsFileData);
-        accountInfoFile.finishWrite(fos);
-
-        SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext);
-
-        assertEquals(false, engine.getMasterSyncAutomatically(0));
-        assertEquals(true, engine.getMasterSyncAutomatically(1));
-        assertEquals(true, engine.getMasterSyncAutomatically(2));
-
-    }
-
-    @MediumTest
-    public void testAuthorityRenaming() throws Exception {
-        final Account account1 = new Account("acc1", "type1");
-        final Account account2 = new Account("acc2", "type2");
-        final String authorityContacts = "contacts";
-        final String authorityCalendar = "calendar";
-        final String authorityOther = "other";
-        final String authorityContactsNew = "com.android.contacts";
-        final String authorityCalendarNew = "com.android.calendar";
-
-        MockContentResolver mockResolver = new MockContentResolver();
-
-        final TestContext testContext = new TestContext(mockResolver, getContext());
-
-        byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
-                + "<accounts>\n"
-                + "<authority id=\"0\" account=\"acc1\" type=\"type1\" authority=\"contacts\" />\n"
-                + "<authority id=\"1\" account=\"acc1\" type=\"type1\" authority=\"calendar\" />\n"
-                + "<authority id=\"2\" account=\"acc1\" type=\"type1\" authority=\"other\" />\n"
-                + "<authority id=\"3\" account=\"acc2\" type=\"type2\" authority=\"contacts\" />\n"
-                + "<authority id=\"4\" account=\"acc2\" type=\"type2\" authority=\"calendar\" />\n"
-                + "<authority id=\"5\" account=\"acc2\" type=\"type2\" authority=\"other\" />\n"
-                + "<authority id=\"6\" account=\"acc2\" type=\"type2\" enabled=\"false\""
-                + " authority=\"com.android.calendar\" />\n"
-                + "<authority id=\"7\" account=\"acc2\" type=\"type2\" enabled=\"false\""
-                + " authority=\"com.android.contacts\" />\n"
-                + "</accounts>\n").getBytes();
-
-        File syncDir = new File(new File(testContext.getFilesDir(), "system"), "sync");
-        syncDir.mkdirs();
-        AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
-        FileOutputStream fos = accountInfoFile.startWrite();
-        fos.write(accountsFileData);
-        accountInfoFile.finishWrite(fos);
-
-        SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext);
-
-        assertEquals(false, engine.getSyncAutomatically(account1, 0, authorityContacts));
-        assertEquals(false, engine.getSyncAutomatically(account1, 0, authorityCalendar));
-        assertEquals(true, engine.getSyncAutomatically(account1, 0, authorityOther));
-        assertEquals(true, engine.getSyncAutomatically(account1, 0, authorityContactsNew));
-        assertEquals(true, engine.getSyncAutomatically(account1, 0, authorityCalendarNew));
-
-        assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityContacts));
-        assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityCalendar));
-        assertEquals(true, engine.getSyncAutomatically(account2, 0, authorityOther));
-        assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityContactsNew));
-        assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityCalendarNew));
-    }
-
-    @SmallTest
-    public void testSyncableMigration() throws Exception {
-        final Account account = new Account("acc", "type");
-
-        MockContentResolver mockResolver = new MockContentResolver();
-
-        final TestContext testContext = new TestContext(mockResolver, getContext());
-
-        byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
-                + "<accounts>\n"
-                + "<authority id=\"0\" account=\"acc\" authority=\"other1\" />\n"
-                + "<authority id=\"1\" account=\"acc\" type=\"type\" authority=\"other2\" />\n"
-                + "<authority id=\"2\" account=\"acc\" type=\"type\" syncable=\"false\""
-                + " authority=\"other3\" />\n"
-                + "<authority id=\"3\" account=\"acc\" type=\"type\" syncable=\"true\""
-                + " authority=\"other4\" />\n"
-                + "</accounts>\n").getBytes();
-
-        File syncDir = new File(new File(testContext.getFilesDir(), "system"), "sync");
-        syncDir.mkdirs();
-        AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
-        FileOutputStream fos = accountInfoFile.startWrite();
-        fos.write(accountsFileData);
-        accountInfoFile.finishWrite(fos);
-
-        SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext);
-
-        assertEquals(-1, engine.getIsSyncable(account, 0, "other1"));
-        assertEquals(1, engine.getIsSyncable(account, 0, "other2"));
-        assertEquals(0, engine.getIsSyncable(account, 0, "other3"));
-        assertEquals(1, engine.getIsSyncable(account, 0, "other4"));
-    }
-
-    /**
-     * Verify that the API cannot cause a run-time reboot by passing in the empty string as an
-     * authority. The problem here is that
-     * {@link SyncStorageEngine#getOrCreateAuthorityLocked(account, provider)} would register
-     * an empty authority which causes a RTE in {@link SyncManager#scheduleReadyPeriodicSyncs()}.
-     * This is not strictly a SSE test, but it does depend on the SSE data structures.
-     */
-    @SmallTest
-    public void testExpectedIllegalArguments() throws Exception {
-        try {
-            ContentResolver.setSyncAutomatically(account1, "", true);
-            fail("empty provider string should throw IllegalArgumentException");
-        } catch (IllegalArgumentException expected) {}
-
-        try {
-            ContentResolver.addPeriodicSync(account1, "", Bundle.EMPTY, 84000L);
-            fail("empty provider string should throw IllegalArgumentException");
-        } catch (IllegalArgumentException expected) {}
-
-        try {
-            ContentResolver.removePeriodicSync(account1, "", Bundle.EMPTY);
-            fail("empty provider string should throw IllegalArgumentException");
-        } catch (IllegalArgumentException expected) {}
-
-        try {
-            ContentResolver.cancelSync(account1, "");
-            fail("empty provider string should throw IllegalArgumentException");
-        } catch (IllegalArgumentException expected) {}
-
-        try {
-            ContentResolver.setIsSyncable(account1, "", 0);
-            fail("empty provider string should throw IllegalArgumentException");
-        } catch (IllegalArgumentException expected) {}
-
-        try {
-            ContentResolver.cancelSync(account1, "");
-            fail("empty provider string should throw IllegalArgumentException");
-        } catch (IllegalArgumentException expected) {}
-
-        try {
-            ContentResolver.requestSync(account1, "", Bundle.EMPTY);
-            fail("empty provider string should throw IllegalArgumentException");
-        } catch (IllegalArgumentException expected) {}
-
-        try {
-            ContentResolver.getSyncStatus(account1, "");
-            fail("empty provider string should throw IllegalArgumentException");
-        } catch (IllegalArgumentException expected) {}
-
-        // Make sure we aren't blocking null account/provider for those functions that use it
-        // to specify ALL accounts/providers.
-        ContentResolver.requestSync(null, null, Bundle.EMPTY);
-        ContentResolver.cancelSync(null, null);
-    }
-}
-
-class TestContext extends ContextWrapper {
-
-    ContentResolver mResolver;
-
-    private final Context mRealContext;
-
-    public TestContext(ContentResolver resolver, Context realContext) {
-        super(new RenamingDelegatingContext(new MockContext(), realContext, "test."));
-        mRealContext = realContext;
-        mResolver = resolver;
-    }
-
-    @Override
-    public Resources getResources() {
-        return mRealContext.getResources();
-    }
-
-    @Override
-    public File getFilesDir() {
-        return mRealContext.getFilesDir();
-    }
-
-    @Override
-    public void enforceCallingOrSelfPermission(String permission, String message) {
-    }
-
-    @Override
-    public void sendBroadcast(Intent intent) {
-    }
-
-    @Override
-    public ContentResolver getContentResolver() {
-        return mResolver;
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index ab0bfefb..cd39285 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -98,12 +98,6 @@
         this.context = injector.context;
     }
 
-    @Override
-    public boolean isPasswordBlacklisted(int userId, String password) {
-        return false;
-    }
-
-
     public void notifyChangeToContentObserver(Uri uri, int userHandle) {
         ContentObserver co = mMockInjector.mContentObservers.get(new Pair<>(uri, userHandle));
         if (co != null) {
@@ -220,11 +214,6 @@
         }
 
         @Override
-        PasswordBlacklist newPasswordBlacklist(File file) {
-            return services.passwordBlacklist;
-        }
-
-        @Override
         boolean storageManagerIsFileBasedEncryptionEnabled() {
             return services.storageManager.isFileBasedEncryptionEnabled();
         }
@@ -393,8 +382,8 @@
         }
 
         @Override
-        void settingsSystemPutString(String name, String value) {
-            services.settings.settingsSystemPutString(name, value);
+        void settingsSystemPutStringForUser(String name, String value, int userId) {
+            services.settings.settingsSystemPutStringForUser(name, value, userId);
         }
 
         @Override
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 fe47de6..b76064b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -3454,18 +3454,19 @@
                 dpm.setSystemSetting(admin1, Settings.System.SCREEN_BRIGHTNESS_FOR_VR, "0"));
     }
 
-    public void testSetSystemSettingFailWithPO() throws Exception {
-        setupProfileOwner();
-        assertExpectException(SecurityException.class, null, () ->
-                dpm.setSystemSetting(admin1, Settings.System.SCREEN_BRIGHTNESS, "0"));
-    }
-
-    public void testSetSystemSetting() throws Exception {
+    public void testSetSystemSettingWithDO() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setupDeviceOwner();
         dpm.setSystemSetting(admin1, Settings.System.SCREEN_BRIGHTNESS, "0");
-        verify(getServices().settings).settingsSystemPutString(
-                Settings.System.SCREEN_BRIGHTNESS, "0");
+        verify(getServices().settings).settingsSystemPutStringForUser(
+                Settings.System.SCREEN_BRIGHTNESS, "0", UserHandle.USER_SYSTEM);
+    }
+
+    public void testSetSystemSettingWithPO() throws Exception {
+        setupProfileOwner();
+        dpm.setSystemSetting(admin1, Settings.System.SCREEN_BRIGHTNESS, "0");
+        verify(getServices().settings).settingsSystemPutStringForUser(
+            Settings.System.SCREEN_BRIGHTNESS, "0", DpmMockContext.CALLER_USER_HANDLE);
     }
 
     public void testSetTime() throws Exception {
@@ -4191,36 +4192,6 @@
         assertTrue(dpm.clearResetPasswordToken(admin1));
     }
 
-    public void testSetPasswordBlacklistCannotBeCalledByNonAdmin() throws Exception {
-        assertExpectException(SecurityException.class, /* messageRegex= */ null,
-                () -> dpm.setPasswordBlacklist(admin1, null, null));
-        verifyZeroInteractions(getServices().passwordBlacklist);
-    }
-
-    public void testClearingPasswordBlacklistDoesNotCreateNewBlacklist() throws Exception {
-        setupProfileOwner();
-        dpm.setPasswordBlacklist(admin1, null, null);
-        verifyZeroInteractions(getServices().passwordBlacklist);
-    }
-
-    public void testSetPasswordBlacklistCreatesNewBlacklist() throws Exception {
-        final String name = "myblacklist";
-        final List<String> explicit = Arrays.asList("password", "letmein");
-        setupProfileOwner();
-        dpm.setPasswordBlacklist(admin1, name, explicit);
-        verify(getServices().passwordBlacklist).savePasswordBlacklist(name, explicit);
-    }
-
-    public void testSetPasswordBlacklistOnlyConvertsExplicitToLowerCase() throws Exception {
-        final List<String> mixedCase = Arrays.asList("password", "LETMEIN", "FooTBAll");
-        final List<String> lowerCase = Arrays.asList("password", "letmein", "football");
-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
-        setupDeviceOwner();
-        final String name = "Name of the Blacklist";
-        dpm.setPasswordBlacklist(admin1, name, mixedCase);
-        verify(getServices().passwordBlacklist).savePasswordBlacklist(name, lowerCase);
-    }
-
     public void testIsActivePasswordSufficient() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         mContext.packageName = admin1.getPackageName();
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 34c69f5..e753df1 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -96,7 +96,6 @@
     public final IBackupManager ibackupManager;
     public final IAudioService iaudioService;
     public final LockPatternUtils lockPatternUtils;
-    public final PasswordBlacklist passwordBlacklist;
     public final StorageManagerForMock storageManager;
     public final WifiManager wifiManager;
     public final SettingsForMock settings;
@@ -135,7 +134,6 @@
         ibackupManager = mock(IBackupManager.class);
         iaudioService = mock(IAudioService.class);
         lockPatternUtils = mock(LockPatternUtils.class);
-        passwordBlacklist = mock(PasswordBlacklist.class);
         storageManager = mock(StorageManagerForMock.class);
         wifiManager = mock(WifiManager.class);
         settings = mock(SettingsForMock.class);
@@ -419,7 +417,7 @@
         public void settingsGlobalPutString(String name, String value) {
         }
 
-        public void settingsSystemPutString(String name, String value) {
+        public void settingsSystemPutStringForUser(String name, String value, int callingUserId) {
         }
 
         public int settingsGlobalGetInt(String name, int value) {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/PasswordBlacklistTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/PasswordBlacklistTest.java
deleted file mode 100644
index 1b3fc2c..0000000
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/PasswordBlacklistTest.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.devicepolicy;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Unit tests for {@link PasswordBlacklist}.
- *
- * bit FrameworksServicesTests:com.android.server.devicepolicy.PasswordBlacklistTest
- * runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/devicepolicy/PasswordBlacklistTest.java
- */
-@RunWith(AndroidJUnit4.class)
-public final class PasswordBlacklistTest {
-    private File mBlacklistFile;
-    private PasswordBlacklist mBlacklist;
-
-    @Before
-    public void setUp() throws IOException {
-        mBlacklistFile = File.createTempFile("pwdbl", null);
-        mBlacklist = new PasswordBlacklist(mBlacklistFile);
-    }
-
-    @After
-    public void tearDown() {
-        mBlacklist.delete();
-    }
-
-    @Test
-    public void matchIsExact() {
-        // Note: Case sensitivity is handled by the user of PasswordBlacklist by normalizing the
-        // values stored in and tested against it.
-        mBlacklist.savePasswordBlacklist("matchIsExact", Arrays.asList("password", "qWERty"));
-        assertTrue(mBlacklist.isPasswordBlacklisted("password"));
-        assertTrue(mBlacklist.isPasswordBlacklisted("qWERty"));
-        assertFalse(mBlacklist.isPasswordBlacklisted("Password"));
-        assertFalse(mBlacklist.isPasswordBlacklisted("qwert"));
-        assertFalse(mBlacklist.isPasswordBlacklisted("letmein"));
-    }
-
-    @Test
-    public void matchIsNotRegex() {
-        mBlacklist.savePasswordBlacklist("matchIsNotRegex", Arrays.asList("a+b*"));
-        assertTrue(mBlacklist.isPasswordBlacklisted("a+b*"));
-        assertFalse(mBlacklist.isPasswordBlacklisted("aaaa"));
-        assertFalse(mBlacklist.isPasswordBlacklisted("abbbb"));
-        assertFalse(mBlacklist.isPasswordBlacklisted("aaaa"));
-    }
-
-    @Test
-    public void matchFailsSafe() throws IOException {
-        try (FileOutputStream fos = new FileOutputStream(mBlacklistFile)) {
-            // Write a malformed blacklist file
-            fos.write(17);
-        }
-        assertTrue(mBlacklist.isPasswordBlacklisted("anything"));
-        assertTrue(mBlacklist.isPasswordBlacklisted("at"));
-        assertTrue(mBlacklist.isPasswordBlacklisted("ALL"));
-    }
-
-    @Test
-    public void blacklistCanBeNamed() {
-        final String name = "identifier";
-        mBlacklist.savePasswordBlacklist(name, Arrays.asList("one", "two", "three"));
-        assertEquals(mBlacklist.getName(), name);
-    }
-
-    @Test
-    public void reportsTheCorrectNumberOfEntries() {
-        mBlacklist.savePasswordBlacklist("Count Entries", Arrays.asList("1", "2", "3", "4"));
-        assertEquals(mBlacklist.getSize(), 4);
-    }
-
-    @Test
-    public void reportsBlacklistFile() {
-        assertEquals(mBlacklistFile, mBlacklist.getFile());
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
index 81a73efd..b8d2c3e 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
@@ -33,6 +33,11 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -42,8 +47,8 @@
 import android.security.keystore.AndroidKeyStoreSecretKey;
 import android.security.keystore.KeyGenParameterSpec;
 import android.security.keystore.KeyProperties;
-import android.security.keystore.recovery.KeyDerivationParams;
 import android.security.keystore.recovery.KeyChainSnapshot;
+import android.security.keystore.recovery.KeyDerivationParams;
 import android.security.keystore.recovery.RecoveryController;
 import android.security.keystore.recovery.WrappedApplicationKey;
 import android.support.test.InstrumentationRegistry;
@@ -59,6 +64,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
 
 import java.io.File;
 import java.nio.charset.StandardCharsets;
@@ -94,6 +100,7 @@
 
     @Mock private PlatformKeyManager mPlatformKeyManager;
     @Mock private RecoverySnapshotListenersStorage mSnapshotListenersStorage;
+    @Spy private TestOnlyInsecureCertificateHelper mTestOnlyInsecureCertificateHelper;
 
     private RecoverySnapshotStorage mRecoverySnapshotStorage;
     private RecoverableKeyStoreDb mRecoverableKeyStoreDb;
@@ -130,7 +137,8 @@
                 TEST_CREDENTIAL_TYPE,
                 TEST_CREDENTIAL,
                 /*credentialUpdated=*/ false,
-                mPlatformKeyManager);
+                mPlatformKeyManager,
+                mTestOnlyInsecureCertificateHelper);
 
         mWrappingKey = generateAndroidKeyStoreKey();
         mEncryptKey = new PlatformEncryptionKey(TEST_GENERATION_ID, mWrappingKey);
@@ -284,6 +292,100 @@
     }
 
     @Test
+    public void run_InTestModeWithWhitelistedCredentials() throws Exception {
+        mRecoverableKeyStoreDb.setServerParams(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE);
+        mRecoverableKeyStoreDb.setPlatformKeyGenerationId(TEST_USER_ID, TEST_GENERATION_ID);
+        addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
+        mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
+
+        // Enter test mode with whitelisted credentials
+        when(mTestOnlyInsecureCertificateHelper.isTestOnlyCertificate(any())).thenReturn(true);
+        when(mTestOnlyInsecureCertificateHelper.doesCredentailSupportInsecureMode(anyInt(), any()))
+                .thenReturn(true);
+        mKeySyncTask.run();
+
+        verify(mTestOnlyInsecureCertificateHelper)
+                .getDefaultCertificateAliasIfEmpty(eq(TEST_ROOT_CERT_ALIAS));
+
+        // run whitelist checks
+        verify(mTestOnlyInsecureCertificateHelper)
+                .doesCredentailSupportInsecureMode(anyInt(), any());
+        verify(mTestOnlyInsecureCertificateHelper)
+                .keepOnlyWhitelistedInsecureKeys(any());
+
+        KeyChainSnapshot keyChainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
+        assertNotNull(keyChainSnapshot); // created snapshot
+        List<WrappedApplicationKey> applicationKeys = keyChainSnapshot.getWrappedApplicationKeys();
+        assertThat(applicationKeys).hasSize(0); // non whitelisted key is not included
+    }
+
+    @Test
+    public void run_InTestModeWithNonWhitelistedCredentials() throws Exception {
+        mRecoverableKeyStoreDb.setServerParams(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE);
+        mRecoverableKeyStoreDb.setPlatformKeyGenerationId(TEST_USER_ID, TEST_GENERATION_ID);
+        addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
+        mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
+
+        // Enter test mode with non whitelisted credentials
+        when(mTestOnlyInsecureCertificateHelper.isTestOnlyCertificate(any())).thenReturn(true);
+        when(mTestOnlyInsecureCertificateHelper.doesCredentailSupportInsecureMode(anyInt(), any()))
+                .thenReturn(false);
+        mKeySyncTask.run();
+
+        assertNull(mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID)); // not created
+        verify(mTestOnlyInsecureCertificateHelper)
+                .getDefaultCertificateAliasIfEmpty(eq(TEST_ROOT_CERT_ALIAS));
+        verify(mTestOnlyInsecureCertificateHelper)
+                .doesCredentailSupportInsecureMode(anyInt(), any());
+    }
+
+    @Test
+    public void run_doesNotFilterCredentialsAndAliasesInProd() throws Exception {
+        mRecoverableKeyStoreDb.setServerParams(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE);
+        mRecoverableKeyStoreDb.setPlatformKeyGenerationId(TEST_USER_ID, TEST_GENERATION_ID);
+        addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
+        mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
+
+        mKeySyncTask.run();
+        assertNotNull(mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID));
+
+        verify(mTestOnlyInsecureCertificateHelper)
+                .getDefaultCertificateAliasIfEmpty(eq(TEST_ROOT_CERT_ALIAS));
+        verify(mTestOnlyInsecureCertificateHelper, atLeast(1))
+                .isTestOnlyCertificate(eq(TEST_ROOT_CERT_ALIAS));
+
+        // no whitelists check
+        verify(mTestOnlyInsecureCertificateHelper, never())
+                .doesCredentailSupportInsecureMode(anyInt(), any());
+        verify(mTestOnlyInsecureCertificateHelper, never())
+                .keepOnlyWhitelistedInsecureKeys(any());
+    }
+
+    @Test
+    public void run_replacesNullActiveRootAliasWithDefaultValue() throws Exception {
+        mRecoverableKeyStoreDb.setServerParams(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE);
+        mRecoverableKeyStoreDb.setPlatformKeyGenerationId(TEST_USER_ID, TEST_GENERATION_ID);
+        addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
+        mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
+        mRecoverableKeyStoreDb.setActiveRootOfTrust(TEST_USER_ID, TEST_RECOVERY_AGENT_UID,
+                /*alias=*/ null);
+
+        when(mTestOnlyInsecureCertificateHelper.getDefaultCertificateAliasIfEmpty(null))
+                .thenReturn(TEST_ROOT_CERT_ALIAS); // override default.
+        mKeySyncTask.run();
+
+        verify(mTestOnlyInsecureCertificateHelper).getDefaultCertificateAliasIfEmpty(null);
+    }
+
+    @Test
     public void run_sendsEncryptedKeysIfAvailableToSync_withRawPublicKey() throws Exception {
         mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
                 TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
@@ -398,7 +500,8 @@
                 CREDENTIAL_TYPE_PASSWORD,
                 "password",
                 /*credentialUpdated=*/ false,
-                mPlatformKeyManager);
+                mPlatformKeyManager,
+                mTestOnlyInsecureCertificateHelper);
 
         mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
                 TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
@@ -424,7 +527,8 @@
                 CREDENTIAL_TYPE_PASSWORD,
                 /*credential=*/ "1234",
                 /*credentialUpdated=*/ false,
-                mPlatformKeyManager);
+                mPlatformKeyManager,
+                mTestOnlyInsecureCertificateHelper);
 
         mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
                 TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
@@ -451,7 +555,8 @@
                 CREDENTIAL_TYPE_PATTERN,
                 "12345",
                 /*credentialUpdated=*/ false,
-                mPlatformKeyManager);
+                mPlatformKeyManager,
+                mTestOnlyInsecureCertificateHelper);
 
         mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
                 TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
@@ -532,7 +637,8 @@
           /*credentialType=*/ 3,
           "12345",
           /*credentialUpdated=*/ false,
-          mPlatformKeyManager);
+          mPlatformKeyManager,
+          mTestOnlyInsecureCertificateHelper);
 
       addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
 
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index 18a3885..a98e291 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -67,6 +68,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
 
 import java.io.File;
 import java.nio.charset.StandardCharsets;
@@ -93,6 +95,8 @@
     private static final String ROOT_CERTIFICATE_ALIAS = "";
     private static final String DEFAULT_ROOT_CERT_ALIAS =
             TrustedRootCertificates.GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS;
+    private static final String INSECURE_CERTIFICATE_ALIAS =
+            TrustedRootCertificates.TEST_ONLY_INSECURE_CERTIFICATE_ALIAS;
     private static final String TEST_SESSION_ID = "karlin";
     private static final byte[] TEST_PUBLIC_KEY = new byte[] {
         (byte) 0x30, (byte) 0x59, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x07, (byte) 0x2a,
@@ -160,6 +164,7 @@
     @Mock private KeyguardManager mKeyguardManager;
     @Mock private PlatformKeyManager mPlatformKeyManager;
     @Mock private ApplicationKeyStorage mApplicationKeyStorage;
+    @Spy private TestOnlyInsecureCertificateHelper mTestOnlyInsecureCertificateHelper;
 
     private RecoverableKeyStoreDb mRecoverableKeyStoreDb;
     private File mDatabaseFile;
@@ -195,7 +200,8 @@
                 mRecoverySnapshotStorage,
                 mMockListenersStorage,
                 mPlatformKeyManager,
-                mApplicationKeyStorage);
+                mApplicationKeyStorage,
+                mTestOnlyInsecureCertificateHelper);
     }
 
     @After
@@ -300,6 +306,9 @@
         mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS,
                 TestData.getCertXmlWithSerial(certSerial));
 
+        verify(mTestOnlyInsecureCertificateHelper, atLeast(1))
+                .getDefaultCertificateAliasIfEmpty(ROOT_CERTIFICATE_ALIAS);
+
         assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isFalse();
         assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
                 DEFAULT_ROOT_CERT_ALIAS)).isEqualTo(TestData.CERT_PATH_1);
@@ -309,6 +318,67 @@
     }
 
     @Test
+    public void initRecoveryService_triesToFilterRootAlias() throws Exception {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+        long certSerial = 1000L;
+        mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, false);
+
+        mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS,
+                TestData.getCertXmlWithSerial(certSerial));
+
+        verify(mTestOnlyInsecureCertificateHelper, atLeast(1))
+                .getDefaultCertificateAliasIfEmpty(eq(ROOT_CERTIFICATE_ALIAS));
+
+        verify(mTestOnlyInsecureCertificateHelper, atLeast(1))
+                .getRootCertificate(eq(DEFAULT_ROOT_CERT_ALIAS));
+
+        String activeRootAlias = mRecoverableKeyStoreDb.getActiveRootOfTrust(userId, uid);
+        assertThat(activeRootAlias).isEqualTo(DEFAULT_ROOT_CERT_ALIAS);
+
+    }
+
+    @Test
+    public void initRecoveryService_usesProdCertificateForEmptyRootAlias() throws Exception {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+        long certSerial = 1000L;
+        mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, false);
+
+        mRecoverableKeyStoreManager.initRecoveryService(/*rootCertificateAlias=*/ "",
+                TestData.getCertXmlWithSerial(certSerial));
+
+        verify(mTestOnlyInsecureCertificateHelper, atLeast(1))
+                .getDefaultCertificateAliasIfEmpty(eq(""));
+
+        verify(mTestOnlyInsecureCertificateHelper, atLeast(1))
+                .getRootCertificate(eq(DEFAULT_ROOT_CERT_ALIAS));
+
+        String activeRootAlias = mRecoverableKeyStoreDb.getActiveRootOfTrust(userId, uid);
+        assertThat(activeRootAlias).isEqualTo(DEFAULT_ROOT_CERT_ALIAS);
+    }
+
+    @Test
+    public void initRecoveryService_usesProdCertificateForNullRootAlias() throws Exception {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+        long certSerial = 1000L;
+        mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, false);
+
+        mRecoverableKeyStoreManager.initRecoveryService(/*rootCertificateAlias=*/ null,
+                TestData.getCertXmlWithSerial(certSerial));
+
+        verify(mTestOnlyInsecureCertificateHelper, atLeast(1))
+                .getDefaultCertificateAliasIfEmpty(null);
+
+        verify(mTestOnlyInsecureCertificateHelper, atLeast(1))
+                .getRootCertificate(eq(DEFAULT_ROOT_CERT_ALIAS));
+
+        String activeRootAlias = mRecoverableKeyStoreDb.getActiveRootOfTrust(userId, uid);
+        assertThat(activeRootAlias).isEqualTo(DEFAULT_ROOT_CERT_ALIAS);
+    }
+
+    @Test
     public void initRecoveryService_regeneratesCounterId() throws Exception {
         int uid = Binder.getCallingUid();
         int userId = UserHandle.getCallingUserId();
@@ -417,6 +487,24 @@
     }
 
     @Test
+    public void initRecoveryServiceWithSigFile_usesProdCertificateForNullRootAlias()
+            throws Exception {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+        long certSerial = 1000L;
+        mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, false);
+
+        mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile(
+                /*rootCertificateAlias=*/null, TestData.getCertXml(), TestData.getSigXml());
+
+        verify(mTestOnlyInsecureCertificateHelper, atLeast(1))
+                .getDefaultCertificateAliasIfEmpty(null);
+
+        verify(mTestOnlyInsecureCertificateHelper, atLeast(1))
+                .getRootCertificate(eq(DEFAULT_ROOT_CERT_ALIAS));
+    }
+
+    @Test
     public void initRecoveryServiceWithSigFile_throwsIfNullCertFile() throws Exception {
         try {
             mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile(
@@ -453,6 +541,18 @@
     }
 
     @Test
+    public void initRecoveryServiceWithSigFile_throwsIfTestAliasUsedWithProdCert()
+            throws Exception {
+        try {
+        mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile(
+                INSECURE_CERTIFICATE_ALIAS, TestData.getCertXml(), TestData.getSigXml());
+            fail("should have thrown");
+        } catch (ServiceSpecificException e) {
+            assertThat(e.getMessage()).contains("signature over the cert file is invalid");
+        }
+    }
+
+    @Test
     public void initRecoveryServiceWithSigFile_throwsIfInvalidFileSignature() throws Exception {
         byte[] modifiedCertXml = TestData.getCertXml();
         modifiedCertXml[modifiedCertXml.length - 1] = 0;  // Change the last new line char to a zero
@@ -712,7 +812,8 @@
     }
 
     @Test
-    public void recoverKeyChainSnapshot_throwsIfFailedToDecryptAllApplicationKeys() throws Exception {
+    public void recoverKeyChainSnapshot_throwsIfFailedToDecryptAllApplicationKeys()
+            throws Exception {
         mRecoverableKeyStoreManager.startRecoverySession(
                 TEST_SESSION_ID,
                 TEST_PUBLIC_KEY,
@@ -792,7 +893,8 @@
     }
 
     @Test
-    public void recoverKeyChainSnapshot_worksOnOtherApplicationKeysIfOneDecryptionFails() throws Exception {
+    public void recoverKeyChainSnapshot_worksOnOtherApplicationKeysIfOneDecryptionFails()
+            throws Exception {
         mRecoverableKeyStoreManager.startRecoverySession(
                 TEST_SESSION_ID,
                 TEST_PUBLIC_KEY,
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java
index 4b059c6..9b2c853 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java
@@ -14,8 +14,12 @@
 import java.security.cert.CertPath;
 import java.security.spec.ECPrivateKeySpec;
 
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
 public final class TestData {
 
+    private static final String KEY_ALGORITHM = "AES";
     private static final long DEFAULT_SERIAL = 1000;
     private static final String CERT_PATH_ENCODING = "PkiPath";
 
@@ -308,4 +312,10 @@
         KeyFactory keyFactory = KeyFactory.getInstance("EC");
         return keyFactory.generatePrivate(new ECPrivateKeySpec(priv, SecureBox.EC_PARAM_SPEC));
     }
+
+    public static SecretKey generateKey() throws Exception {
+        KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
+        keyGenerator.init(/*keySize=*/ 256);
+        return keyGenerator.generateKey();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java
new file mode 100644
index 0000000..bc50c9e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java
@@ -0,0 +1,128 @@
+package com.android.server.locksettings.recoverablekeystore;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+import android.security.keystore.recovery.TrustedRootCertificates;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import com.android.internal.widget.LockPatternUtils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashMap;
+import java.security.cert.X509Certificate;
+import java.util.Map;
+import javax.crypto.SecretKey;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TestOnlyInsecureCertificateHelperTest {
+    private final TestOnlyInsecureCertificateHelper mHelper
+            = new TestOnlyInsecureCertificateHelper();
+
+    @Test
+    public void testDoesCredentailSupportInsecureMode_forNonWhitelistedPassword() throws Exception {
+        assertThat(mHelper.doesCredentailSupportInsecureMode(
+                LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "secret12345")).isFalse();
+        assertThat(mHelper.doesCredentailSupportInsecureMode(
+                LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "1234")).isFalse();
+    }
+
+    @Test
+    public void testDoesCredentailSupportInsecureMode_forWhitelistedPassword() throws Exception {
+        assertThat(mHelper.doesCredentailSupportInsecureMode(
+                LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+                TrustedRootCertificates.INSECURE_PASSWORD_PREFIX)).isTrue();
+
+        assertThat(mHelper.doesCredentailSupportInsecureMode(
+                LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+                TrustedRootCertificates.INSECURE_PASSWORD_PREFIX + "12")).isTrue();
+    }
+
+    @Test
+    public void testDoesCredentailSupportInsecureMode_Pattern() throws Exception {
+        assertThat(mHelper.doesCredentailSupportInsecureMode(
+                LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
+                TrustedRootCertificates.INSECURE_PASSWORD_PREFIX)).isFalse();
+        assertThat(mHelper.doesCredentailSupportInsecureMode(
+                LockPatternUtils.CREDENTIAL_TYPE_NONE,
+                TrustedRootCertificates.INSECURE_PASSWORD_PREFIX)).isFalse();
+    }
+
+    @Test
+    public void testIsTestOnlyCertificate() throws Exception {
+        assertThat(mHelper.isTestOnlyCertificate(
+                TrustedRootCertificates.GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS)).isFalse();
+        assertThat(mHelper.isTestOnlyCertificate(
+                TrustedRootCertificates.TEST_ONLY_INSECURE_CERTIFICATE_ALIAS)).isTrue();
+        assertThat(mHelper.isTestOnlyCertificate(
+                "UNKNOWN_ALIAS")).isFalse();
+    }
+
+    @Test
+    public void testKeepOnlyWhitelistedInsecureKeys_emptyKeysList() throws Exception {
+        Map<String, SecretKey> rawKeys = new HashMap<>();
+        Map<String, SecretKey> expectedResult = new HashMap<>();
+
+        Map<String, SecretKey> filteredKeys =
+                mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys);
+        assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet());
+        assertThat(filteredKeys.entrySet()).containsAllIn(rawKeys.entrySet());
+    }
+
+    @Test
+    public void testKeepOnlyWhitelistedInsecureKeys_singleNonWhitelistedKey() throws Exception {
+        Map<String, SecretKey> rawKeys = new HashMap<>();
+        Map<String, SecretKey> expectedResult = new HashMap<>();
+
+        String alias = "secureAlias";
+        rawKeys.put(alias, TestData.generateKey());
+
+        Map<String, SecretKey> filteredKeys =
+                mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys);
+        assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet());
+        assertThat(rawKeys.entrySet()).containsAllIn(filteredKeys.entrySet());
+    }
+
+    @Test
+    public void testKeepOnlyWhitelistedInsecureKeys_singleWhitelistedKey() throws Exception {
+        Map<String, SecretKey> rawKeys = new HashMap<>();
+        Map<String, SecretKey> expectedResult = new HashMap<>();
+
+        String alias = TrustedRootCertificates.INSECURE_KEY_ALIAS_PREFIX;
+        rawKeys.put(alias, TestData.generateKey());
+        expectedResult.put(alias, rawKeys.get(alias));
+
+        Map<String, SecretKey> filteredKeys =
+                mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys);
+        assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet());
+        assertThat(rawKeys.entrySet()).containsAllIn(filteredKeys.entrySet());
+    }
+
+    @Test
+    public void testKeepOnlyWhitelistedInsecureKeys() throws Exception {
+        Map<String, SecretKey> rawKeys = new HashMap<>();
+        Map<String, SecretKey> expectedResult = new HashMap<>();
+
+        String alias = "SECURE_ALIAS" + TrustedRootCertificates.INSECURE_KEY_ALIAS_PREFIX;
+        rawKeys.put(alias, TestData.generateKey());
+
+        alias = TrustedRootCertificates.INSECURE_KEY_ALIAS_PREFIX + "1";
+        rawKeys.put(alias, TestData.generateKey());
+        expectedResult.put(alias, rawKeys.get(alias));
+
+        alias = TrustedRootCertificates.INSECURE_KEY_ALIAS_PREFIX + "2";
+        rawKeys.put(alias, TestData.generateKey());
+        expectedResult.put(alias, rawKeys.get(alias));
+
+        Map<String, SecretKey> filteredKeys =
+                mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys);
+        assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet());
+        assertThat(rawKeys.entrySet()).containsAllIn(filteredKeys.entrySet());
+    }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
index 36136a8..ce74457 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
@@ -206,6 +206,31 @@
     }
 
     @Test
+    public void testShouldExitForAlarm_oldAlarm() {
+        // Cal: today 2:15pm
+        Calendar cal = new GregorianCalendar();
+        cal.set(Calendar.HOUR_OF_DAY, 14);
+        cal.set(Calendar.MINUTE, 15);
+        cal.set(Calendar.SECOND, 0);
+        cal.set(Calendar.MILLISECOND, 0);
+
+        // ScheduleInfo: today 12:16pm  - today 3:15pm
+        mScheduleInfo.days = new int[] {getTodayDay()};
+        mScheduleInfo.startHour = 12;
+        mScheduleInfo.endHour = 3;
+        mScheduleInfo.startMinute = 16;
+        mScheduleInfo.endMinute = 15;
+        mScheduleInfo.exitAtAlarm = true;
+        mScheduleInfo.nextAlarm = 1000; // very old alarm
+
+        mScheduleCalendar.setSchedule(mScheduleInfo);
+        assertTrue(mScheduleCalendar.isInSchedule(cal.getTimeInMillis()));
+
+        // don't exit for an alarm if it's an old alarm
+        assertFalse(mScheduleCalendar.shouldExitForAlarm(1000));
+    }
+
+    @Test
     public void testMaybeSetNextAlarm_settingOff() {
         mScheduleInfo.exitAtAlarm = false;
         mScheduleInfo.nextAlarm = 0;
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 571ed00a..5f01518 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -24,6 +24,7 @@
 import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
 import static android.app.usage.UsageStatsManager.REASON_SUB_PREDICTED_RESTORED;
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_ACTIVE_TIMEOUT;
+import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_START;
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_NOTIFICATION_SEEN;
@@ -186,6 +187,7 @@
     static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10;
     /** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */
     static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11;
+    static final int MSG_REPORT_EXEMPTED_SYNC_START = 12;
 
     long mCheckIdleIntervalMillis;
     long mAppIdleParoleIntervalMillis;
@@ -202,6 +204,8 @@
     long mPredictionTimeoutMillis;
     /** Maximum time a sync adapter associated with a CP should keep the buckets elevated. */
     long mSyncAdapterTimeoutMillis;
+    /** Maximum time an exempted sync should keep the buckets elevated. */
+    long mExemptedSyncAdapterTimeoutMillis;
     /** Maximum time a system interaction should keep the buckets elevated. */
     long mSystemInteractionTimeoutMillis;
 
@@ -375,6 +379,21 @@
         }
     }
 
+    void reportExemptedSyncStart(String packageName, int userId) {
+        if (!mAppIdleEnabled) return;
+
+        final long elapsedRealtime = mInjector.elapsedRealtime();
+
+        synchronized (mAppIdleLock) {
+            AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId,
+                    STANDBY_BUCKET_ACTIVE, REASON_SUB_USAGE_EXEMPTED_SYNC_START,
+                    0,
+                    elapsedRealtime + mExemptedSyncAdapterTimeoutMillis);
+            maybeInformListeners(packageName, userId, elapsedRealtime,
+                    appUsage.currentBucket, appUsage.bucketingReason, false);
+        }
+    }
+
     void setChargingState(boolean charging) {
         synchronized (mAppIdleLock) {
             if (mCharging != charging) {
@@ -1274,6 +1293,11 @@
                 .sendToTarget();
     }
 
+    void postReportExemptedSyncStart(String packageName, int userId) {
+        mHandler.obtainMessage(MSG_REPORT_EXEMPTED_SYNC_START, userId, 0, packageName)
+                .sendToTarget();
+    }
+
     void dumpUser(IndentingPrintWriter idpw, int userId, String pkg) {
         synchronized (mAppIdleLock) {
             mAppIdleHistory.dump(idpw, userId, pkg);
@@ -1488,6 +1512,11 @@
                     checkAndUpdateStandbyState((String) msg.obj, msg.arg1, msg.arg2,
                             mInjector.elapsedRealtime());
                     break;
+
+                case MSG_REPORT_EXEMPTED_SYNC_START:
+                    reportExemptedSyncStart((String) msg.obj, msg.arg1);
+                    break;
+
                 default:
                     super.handleMessage(msg);
                     break;
@@ -1550,6 +1579,7 @@
                 "system_update_usage_duration";
         private static final String KEY_PREDICTION_TIMEOUT = "prediction_timeout";
         private static final String KEY_SYNC_ADAPTER_HOLD_DURATION = "sync_adapter_duration";
+        private static final String KEY_EXEMPTED_SYNC_HOLD_DURATION = "exempted_sync_duration";
         private static final String KEY_SYSTEM_INTERACTION_HOLD_DURATION =
                 "system_interaction_duration";
         public static final long DEFAULT_STRONG_USAGE_TIMEOUT = 1 * ONE_HOUR;
@@ -1557,6 +1587,7 @@
         public static final long DEFAULT_SYSTEM_UPDATE_TIMEOUT = 2 * ONE_HOUR;
         public static final long DEFAULT_SYSTEM_INTERACTION_TIMEOUT = 10 * ONE_MINUTE;
         public static final long DEFAULT_SYNC_ADAPTER_TIMEOUT = 10 * ONE_MINUTE;
+        public static final long DEFAULT_EXEMPTED_SYNC_TIMEOUT = 10 * ONE_MINUTE;
 
         private final KeyValueListParser mParser = new KeyValueListParser(',');
 
@@ -1632,6 +1663,9 @@
                 mSyncAdapterTimeoutMillis = mParser.getDurationMillis
                         (KEY_SYNC_ADAPTER_HOLD_DURATION,
                                 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYNC_ADAPTER_TIMEOUT);
+                mExemptedSyncAdapterTimeoutMillis = mParser.getDurationMillis
+                        (KEY_EXEMPTED_SYNC_HOLD_DURATION,
+                                COMPRESS_TIME ? ONE_MINUTE : DEFAULT_EXEMPTED_SYNC_TIMEOUT);
                 mSystemInteractionTimeoutMillis = mParser.getDurationMillis
                         (KEY_SYSTEM_INTERACTION_HOLD_DURATION,
                                 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYSTEM_INTERACTION_TIMEOUT);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 2258b24..1fbc27b 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -1279,5 +1279,10 @@
         public void onAdminDataAvailable() {
             mAppStandby.onAdminDataAvailable();
         }
+
+        @Override
+        public void reportExemptedSyncStart(String packageName, int userId) {
+            mAppStandby.postReportExemptedSyncStart(packageName, userId);
+        }
     }
 }
diff --git a/tests/net/java/android/app/usage/NetworkStatsManagerTest.java b/tests/net/java/android/app/usage/NetworkStatsManagerTest.java
new file mode 100644
index 0000000..25e1474
--- /dev/null
+++ b/tests/net/java/android/app/usage/NetworkStatsManagerTest.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.usage;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.net.ConnectivityManager;
+import android.net.INetworkStatsService;
+import android.net.INetworkStatsSession;
+import android.net.NetworkStats.Entry;
+import android.net.NetworkStatsHistory;
+import android.net.NetworkTemplate;
+import android.os.RemoteException;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NetworkStatsManagerTest {
+
+    private @Mock INetworkStatsService mService;
+    private @Mock INetworkStatsSession mStatsSession;
+
+    private NetworkStatsManager mManager;
+
+    // TODO: change to NetworkTemplate.MATCH_MOBILE once internal constant rename is merged to aosp.
+    private static final int MATCH_MOBILE_ALL = 1;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mManager = new NetworkStatsManager(InstrumentationRegistry.getContext(), mService);
+    }
+
+    @Test
+    public void testQueryDetails() throws RemoteException {
+        final String subscriberId = "subid";
+        final long startTime = 1;
+        final long endTime = 100;
+        final int uid1 = 10001;
+        final int uid2 = 10002;
+        final int uid3 = 10003;
+
+        Entry uid1Entry1 = new Entry("if1", uid1,
+                android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
+                100, 10, 200, 20, 0);
+
+        Entry uid1Entry2 = new Entry(
+                "if2", uid1,
+                android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
+                100, 10, 200, 20, 0);
+
+        Entry uid2Entry1 = new Entry("if1", uid2,
+                android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
+                150, 10, 250, 20, 0);
+
+        Entry uid2Entry2 = new Entry(
+                "if2", uid2,
+                android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
+                150, 10, 250, 20, 0);
+
+        NetworkStatsHistory history1 = new NetworkStatsHistory(10, 2);
+        history1.recordData(10, 20, uid1Entry1);
+        history1.recordData(20, 30, uid1Entry2);
+
+        NetworkStatsHistory history2 = new NetworkStatsHistory(10, 2);
+        history1.recordData(30, 40, uid2Entry1);
+        history1.recordData(35, 45, uid2Entry2);
+
+
+        when(mService.openSessionForUsageStats(anyInt(), anyString())).thenReturn(mStatsSession);
+        when(mStatsSession.getRelevantUids()).thenReturn(new int[] { uid1, uid2, uid3 });
+
+        when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class),
+                eq(uid1), eq(android.net.NetworkStats.SET_ALL),
+                eq(android.net.NetworkStats.TAG_NONE),
+                eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime)))
+                .then((InvocationOnMock inv) -> {
+                    NetworkTemplate template = inv.getArgument(0);
+                    assertEquals(MATCH_MOBILE_ALL, template.getMatchRule());
+                    assertEquals(subscriberId, template.getSubscriberId());
+                    return history1;
+                });
+
+        when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class),
+                eq(uid2), eq(android.net.NetworkStats.SET_ALL),
+                eq(android.net.NetworkStats.TAG_NONE),
+                eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime)))
+                .then((InvocationOnMock inv) -> {
+                    NetworkTemplate template = inv.getArgument(0);
+                    assertEquals(MATCH_MOBILE_ALL, template.getMatchRule());
+                    assertEquals(subscriberId, template.getSubscriberId());
+                    return history2;
+                });
+
+
+        NetworkStats stats = mManager.queryDetails(
+                ConnectivityManager.TYPE_MOBILE, subscriberId, startTime, endTime);
+
+        NetworkStats.Bucket bucket = new NetworkStats.Bucket();
+
+        // First 2 buckets exactly match entry timings
+        assertTrue(stats.getNextBucket(bucket));
+        assertEquals(10, bucket.getStartTimeStamp());
+        assertEquals(20, bucket.getEndTimeStamp());
+        assertBucketMatches(uid1Entry1, bucket);
+
+        assertTrue(stats.getNextBucket(bucket));
+        assertEquals(20, bucket.getStartTimeStamp());
+        assertEquals(30, bucket.getEndTimeStamp());
+        assertBucketMatches(uid1Entry2, bucket);
+
+        // 30 -> 40: contains uid2Entry1 and half of uid2Entry2
+        assertTrue(stats.getNextBucket(bucket));
+        assertEquals(30, bucket.getStartTimeStamp());
+        assertEquals(40, bucket.getEndTimeStamp());
+        assertEquals(225, bucket.getRxBytes());
+        assertEquals(15, bucket.getRxPackets());
+        assertEquals(375, bucket.getTxBytes());
+        assertEquals(30, bucket.getTxPackets());
+
+        // 40 -> 50: contains half of uid2Entry2
+        assertTrue(stats.getNextBucket(bucket));
+        assertEquals(40, bucket.getStartTimeStamp());
+        assertEquals(50, bucket.getEndTimeStamp());
+        assertEquals(75, bucket.getRxBytes());
+        assertEquals(5, bucket.getRxPackets());
+        assertEquals(125, bucket.getTxBytes());
+        assertEquals(10, bucket.getTxPackets());
+
+        assertFalse(stats.hasNextBucket());
+    }
+
+    @Test
+    public void testQueryDetails_NoSubscriberId() throws RemoteException {
+        final long startTime = 1;
+        final long endTime = 100;
+        final int uid1 = 10001;
+        final int uid2 = 10002;
+
+        when(mService.openSessionForUsageStats(anyInt(), anyString())).thenReturn(mStatsSession);
+        when(mStatsSession.getRelevantUids()).thenReturn(new int[] { uid1, uid2 });
+
+        NetworkStats stats = mManager.queryDetails(
+                ConnectivityManager.TYPE_MOBILE, null, startTime, endTime);
+
+        when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class),
+                anyInt(), anyInt(), anyInt(), anyInt(), anyLong(), anyLong()))
+                .thenReturn(new NetworkStatsHistory(10, 0));
+
+        verify(mStatsSession, times(1)).getHistoryIntervalForUid(
+                argThat((NetworkTemplate t) ->
+                        // No subscriberId: MATCH_MOBILE_WILDCARD template
+                        t.getMatchRule() == NetworkTemplate.MATCH_MOBILE_WILDCARD),
+                eq(uid1), eq(android.net.NetworkStats.SET_ALL),
+                eq(android.net.NetworkStats.TAG_NONE),
+                eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime));
+
+        verify(mStatsSession, times(1)).getHistoryIntervalForUid(
+                argThat((NetworkTemplate t) ->
+                        // No subscriberId: MATCH_MOBILE_WILDCARD template
+                        t.getMatchRule() == NetworkTemplate.MATCH_MOBILE_WILDCARD),
+                eq(uid2), eq(android.net.NetworkStats.SET_ALL),
+                eq(android.net.NetworkStats.TAG_NONE),
+                eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime));
+
+        assertFalse(stats.hasNextBucket());
+    }
+
+    private void assertBucketMatches(Entry expected,
+            NetworkStats.Bucket actual) {
+        assertEquals(expected.uid, actual.getUid());
+        assertEquals(expected.rxBytes, actual.getRxBytes());
+        assertEquals(expected.rxPackets, actual.getRxPackets());
+        assertEquals(expected.txBytes, actual.getTxBytes());
+        assertEquals(expected.txPackets, actual.getTxPackets());
+    }
+}
diff --git a/tests/net/java/android/net/util/InterfaceSetTest.java b/tests/net/java/android/net/util/InterfaceSetTest.java
new file mode 100644
index 0000000..8012838
--- /dev/null
+++ b/tests/net/java/android/net/util/InterfaceSetTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.util;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class InterfaceSetTest {
+    @Test
+    public void testNullNamesIgnored() {
+        final InterfaceSet set = new InterfaceSet(null, "if1", null, "if2", null);
+        assertEquals(2, set.ifnames.size());
+        assertTrue(set.ifnames.contains("if1"));
+        assertTrue(set.ifnames.contains("if2"));
+    }
+
+    @Test
+    public void testToString() {
+        final InterfaceSet set = new InterfaceSet("if1", "if2");
+        final String setString = set.toString();
+        assertTrue(setString.equals("[if1,if2]") || setString.equals("[if2,if1]"));
+    }
+
+    @Test
+    public void testToString_Empty() {
+        final InterfaceSet set = new InterfaceSet(null, null);
+        assertEquals("[]", set.toString());
+    }
+
+    @Test
+    public void testEquals() {
+        assertEquals(new InterfaceSet(null, "if1", "if2"), new InterfaceSet("if2", "if1"));
+        assertEquals(new InterfaceSet(null, null), new InterfaceSet());
+        assertFalse(new InterfaceSet("if1", "if3").equals(new InterfaceSet("if1", "if2")));
+        assertFalse(new InterfaceSet("if1", "if2").equals(new InterfaceSet("if1")));
+        assertFalse(new InterfaceSet().equals(null));
+    }
+}
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index e692652..27f90f2 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -27,8 +27,11 @@
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.notNull;
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
@@ -36,6 +39,7 @@
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -45,18 +49,29 @@
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.res.Resources;
 import android.hardware.usb.UsbManager;
 import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
+import android.net.INetd;
 import android.net.INetworkPolicyManager;
 import android.net.INetworkStatsService;
 import android.net.InterfaceConfiguration;
-import android.net.NetworkRequest;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.MacAddress;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.net.NetworkState;
+import android.net.NetworkUtils;
+import android.net.RouteInfo;
+import android.net.ip.RouterAdvertisementDaemon;
+import android.net.util.InterfaceParams;
+import android.net.util.NetworkConstants;
 import android.net.util.SharedLog;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
@@ -74,10 +89,16 @@
 import android.telephony.CarrierConfigManager;
 import android.test.mock.MockContentResolver;
 
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.StateMachine;
 import com.android.internal.util.test.BroadcastInterceptingContext;
 import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.server.connectivity.tethering.IControlsTethering;
+import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
 import com.android.server.connectivity.tethering.OffloadHardwareInterface;
+import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
 import com.android.server.connectivity.tethering.TetheringDependencies;
+import com.android.server.connectivity.tethering.UpstreamNetworkMonitor;
 
 import org.junit.After;
 import org.junit.Before;
@@ -86,13 +107,21 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.net.Inet4Address;
+import java.net.Inet6Address;
 import java.util.ArrayList;
 import java.util.Vector;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class TetheringTest {
+    private static final int IFINDEX_OFFSET = 100;
+
     private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
+    private static final String TEST_MOBILE_IFNAME = "test_rmnet_data0";
+    private static final String TEST_XLAT_MOBILE_IFNAME = "v4-test_rmnet_data0";
+    private static final String TEST_USB_IFNAME = "test_rndis0";
+    private static final String TEST_WLAN_IFNAME = "test_wlan0";
 
     @Mock private ApplicationInfo mApplicationInfo;
     @Mock private Context mContext;
@@ -103,16 +132,21 @@
     @Mock private MockableSystemProperties mSystemProperties;
     @Mock private OffloadHardwareInterface mOffloadHardwareInterface;
     @Mock private Resources mResources;
-    @Mock private TetheringDependencies mTetheringDependencies;
     @Mock private UsbManager mUsbManager;
     @Mock private WifiManager mWifiManager;
     @Mock private CarrierConfigManager mCarrierConfigManager;
+    @Mock private UpstreamNetworkMonitor mUpstreamNetworkMonitor;
+    @Mock private IPv6TetheringCoordinator mIPv6TetheringCoordinator;
+    @Mock private RouterAdvertisementDaemon mRouterAdvertisementDaemon;
+    @Mock private INetd mNetd;
+
+    private final MockTetheringDependencies mTetheringDependencies =
+            new MockTetheringDependencies();
 
     // Like so many Android system APIs, these cannot be mocked because it is marked final.
     // We have to use the real versions.
     private final PersistableBundle mCarrierConfig = new PersistableBundle();
     private final TestLooper mLooper = new TestLooper();
-    private final String mTestIfname = "test_wlan0";
 
     private Vector<Intent> mIntents;
     private BroadcastInterceptingContext mServiceContext;
@@ -146,23 +180,122 @@
         }
     }
 
+    public class MockTetheringDependencies extends TetheringDependencies {
+        private StateMachine upstreamNetworkMonitorMasterSM;
+        private ArrayList<TetherInterfaceStateMachine> ipv6CoordinatorNotifyList;
+
+        @Override
+        public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) {
+            return mOffloadHardwareInterface;
+        }
+
+        @Override
+        public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx,
+                StateMachine target, SharedLog log, int what) {
+            upstreamNetworkMonitorMasterSM = target;
+            return mUpstreamNetworkMonitor;
+        }
+
+        @Override
+        public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
+                ArrayList<TetherInterfaceStateMachine> notifyList, SharedLog log) {
+            ipv6CoordinatorNotifyList = notifyList;
+            return mIPv6TetheringCoordinator;
+        }
+
+        @Override
+        public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
+            return mRouterAdvertisementDaemon;
+        }
+
+        @Override
+        public INetd getNetdService() {
+            return mNetd;
+        }
+
+        @Override
+        public InterfaceParams getInterfaceParams(String ifName) {
+            final String[] ifaces = new String[] { TEST_USB_IFNAME, TEST_WLAN_IFNAME,
+                    TEST_MOBILE_IFNAME };
+            final int index = ArrayUtils.indexOf(ifaces, ifName);
+            assertTrue("Non-mocked interface: " + ifName, index >= 0);
+            return new InterfaceParams(ifName, index + IFINDEX_OFFSET,
+                    MacAddress.ALL_ZEROS_ADDRESS);
+        }
+    }
+
+    private static NetworkState buildMobileUpstreamState(boolean withIPv4, boolean withIPv6,
+            boolean with464xlat) {
+        final NetworkInfo info = new NetworkInfo(ConnectivityManager.TYPE_MOBILE, 0, null, null);
+        info.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
+        final LinkProperties prop = new LinkProperties();
+        prop.setInterfaceName(TEST_MOBILE_IFNAME);
+
+        if (withIPv4) {
+            prop.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0),
+                    NetworkUtils.numericToInetAddress("10.0.0.1"), TEST_MOBILE_IFNAME));
+        }
+
+        if (withIPv6) {
+            prop.addDnsServer(NetworkUtils.numericToInetAddress("2001:db8::2"));
+            prop.addLinkAddress(
+                    new LinkAddress(NetworkUtils.numericToInetAddress("2001:db8::"),
+                            NetworkConstants.RFC7421_PREFIX_LENGTH));
+            prop.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0),
+                    NetworkUtils.numericToInetAddress("2001:db8::1"), TEST_MOBILE_IFNAME));
+        }
+
+        if (with464xlat) {
+            final LinkProperties stackedLink = new LinkProperties();
+            stackedLink.setInterfaceName(TEST_XLAT_MOBILE_IFNAME);
+            stackedLink.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0),
+                    NetworkUtils.numericToInetAddress("192.0.0.1"), TEST_XLAT_MOBILE_IFNAME));
+
+            prop.addStackedLink(stackedLink);
+        }
+
+
+        final NetworkCapabilities capabilities = new NetworkCapabilities()
+                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);;
+        return new NetworkState(info, prop, capabilities, new Network(100), null, "netid");
+    }
+
+    private static NetworkState buildMobileIPv4UpstreamState() {
+        return buildMobileUpstreamState(true, false, false);
+    }
+
+    private static NetworkState buildMobileIPv6UpstreamState() {
+        return buildMobileUpstreamState(false, true, false);
+    }
+
+    private static NetworkState buildMobileDualStackUpstreamState() {
+        return buildMobileUpstreamState(true, true, false);
+    }
+
+    private static NetworkState buildMobile464xlatUpstreamState() {
+        return buildMobileUpstreamState(false, true, true);
+    }
+
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         when(mResources.getStringArray(com.android.internal.R.array.config_tether_dhcp_range))
                 .thenReturn(new String[0]);
         when(mResources.getStringArray(com.android.internal.R.array.config_tether_usb_regexs))
-                .thenReturn(new String[0]);
+                .thenReturn(new String[] { "test_rndis\\d" });
         when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_regexs))
-                .thenReturn(new String[]{ "test_wlan\\d", "test_rndis\\d" });
+                .thenReturn(new String[]{ "test_wlan\\d" });
         when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs))
                 .thenReturn(new String[0]);
         when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
                 .thenReturn(new int[0]);
         when(mNMService.listInterfaces())
-                .thenReturn(new String[]{ "test_rmnet_data0", mTestIfname });
+                .thenReturn(new String[] {
+                        TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME});
         when(mNMService.getInterfaceConfig(anyString()))
                 .thenReturn(new InterfaceConfiguration());
+        when(mRouterAdvertisementDaemon.start())
+                .thenReturn(true);
 
         mServiceContext = new MockContext(mContext);
         mContentResolver = new MockContentResolver(mServiceContext);
@@ -176,8 +309,6 @@
         };
         mServiceContext.registerReceiver(mBroadcastReceiver,
                 new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
-        when(mTetheringDependencies.getOffloadHardwareInterface(
-                any(Handler.class), any(SharedLog.class))).thenReturn(mOffloadHardwareInterface);
         mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
                                    mLooper.getLooper(), mSystemProperties,
                                    mTetheringDependencies);
@@ -264,10 +395,10 @@
     }
 
     private void verifyInterfaceServingModeStarted() throws Exception {
-        verify(mNMService, times(1)).getInterfaceConfig(mTestIfname);
+        verify(mNMService, times(1)).getInterfaceConfig(TEST_WLAN_IFNAME);
         verify(mNMService, times(1))
-                .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
-        verify(mNMService, times(1)).tetherInterface(mTestIfname);
+                .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
+        verify(mNMService, times(1)).tetherInterface(TEST_WLAN_IFNAME);
     }
 
     private void verifyTetheringBroadcast(String ifname, String whichExtra) {
@@ -287,7 +418,7 @@
         // per-interface state machine to start up, and telling us that
         // hotspot mode is to be started.
         if (emulateInterfaceStatusChanged) {
-            mTethering.interfaceStatusChanged(mTestIfname, true);
+            mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
         }
         sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
         mLooper.dispatchAll();
@@ -297,27 +428,31 @@
         // broadcast indicating that the interface is "available".
         if (emulateInterfaceStatusChanged) {
             verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
-            verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+            verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
         }
         verifyNoMoreInteractions(mConnectivityManager);
         verifyNoMoreInteractions(mNMService);
         verifyNoMoreInteractions(mWifiManager);
     }
 
-    @Test
-    public void testUsbConfiguredBroadcastStartsTethering() throws Exception {
+    private void prepareUsbTethering(NetworkState upstreamState) {
         when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
+        when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
+                .thenReturn(upstreamState);
 
         // Emulate pressing the USB tethering button in Settings UI.
         mTethering.startTethering(TETHERING_USB, null, false);
         mLooper.dispatchAll();
         verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
 
-        // Pretend we receive a USB connected broadcast. Here we also pretend
-        // that the RNDIS function is somehow enabled, so that we see if we
-        // might trip ourselves up.
-        sendUsbBroadcast(true, false, true);
-        mLooper.dispatchAll();
+        mTethering.interfaceStatusChanged(TEST_USB_IFNAME, true);
+    }
+
+    @Test
+    public void testUsbConfiguredBroadcastStartsTethering() throws Exception {
+        NetworkState upstreamState = buildMobileIPv4UpstreamState();
+        prepareUsbTethering(upstreamState);
+
         // This should produce no activity of any kind.
         verifyNoMoreInteractions(mConnectivityManager);
         verifyNoMoreInteractions(mNMService);
@@ -328,6 +463,10 @@
         // Now we should see the start of tethering mechanics (in this case:
         // tetherMatchingInterfaces() which starts by fetching all interfaces).
         verify(mNMService, times(1)).listInterfaces();
+
+        // UpstreamNetworkMonitor should receive selected upstream
+        verify(mUpstreamNetworkMonitor, times(1)).selectPreferredUpstreamType(any());
+        verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(upstreamState.network);
     }
 
     @Test
@@ -348,26 +487,21 @@
         // per-interface state machine to start up, and telling us that
         // hotspot mode is to be started.
         if (emulateInterfaceStatusChanged) {
-            mTethering.interfaceStatusChanged(mTestIfname, true);
+            mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
         }
-        sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, mTestIfname, IFACE_IP_MODE_LOCAL_ONLY);
+        sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_LOCAL_ONLY);
         mLooper.dispatchAll();
 
         verifyInterfaceServingModeStarted();
-        verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+        verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
         verify(mNMService, times(1)).setIpForwardingEnabled(true);
         verify(mNMService, times(1)).startTethering(any(String[].class));
         verifyNoMoreInteractions(mNMService);
         verify(mWifiManager).updateInterfaceIpState(
-                mTestIfname, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
+                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
         verifyNoMoreInteractions(mWifiManager);
-        verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY);
-        // UpstreamNetworkMonitor will be started, and will register two callbacks:
-        // a "listen all" and a "track default".
-        verify(mConnectivityManager, times(1)).registerNetworkCallback(
-                any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
-        verify(mConnectivityManager, times(1)).registerDefaultNetworkCallback(
-                any(NetworkCallback.class), any(Handler.class));
+        verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY);
+        verify(mUpstreamNetworkMonitor, times(1)).start();
         // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
         verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
         verifyNoMoreInteractions(mConnectivityManager);
@@ -375,14 +509,14 @@
         // Emulate externally-visible WifiManager effects, when hotspot mode
         // is being torn down.
         sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
-        mTethering.interfaceRemoved(mTestIfname);
+        mTethering.interfaceRemoved(TEST_WLAN_IFNAME);
         mLooper.dispatchAll();
 
-        verify(mNMService, times(1)).untetherInterface(mTestIfname);
+        verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
         // TODO: Why is {g,s}etInterfaceConfig() called more than once?
-        verify(mNMService, atLeastOnce()).getInterfaceConfig(mTestIfname);
+        verify(mNMService, atLeastOnce()).getInterfaceConfig(TEST_WLAN_IFNAME);
         verify(mNMService, atLeastOnce())
-                .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
+                .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
         verify(mNMService, times(1)).stopTethering();
         verify(mNMService, times(1)).setIpForwardingEnabled(false);
         verifyNoMoreInteractions(mNMService);
@@ -390,7 +524,115 @@
         // Asking for the last error after the per-interface state machine
         // has been reaped yields an unknown interface error.
         assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
-                mTethering.getLastTetherError(mTestIfname));
+                mTethering.getLastTetherError(TEST_WLAN_IFNAME));
+    }
+
+    /**
+     * Send CMD_IPV6_TETHER_UPDATE to TISMs as would be done by IPv6TetheringCoordinator.
+     */
+    private void sendIPv6TetherUpdates(NetworkState upstreamState) {
+        // IPv6TetheringCoordinator must have been notified of downstream
+        verify(mIPv6TetheringCoordinator, times(1)).addActiveDownstream(
+                argThat(sm -> sm.linkProperties().getInterfaceName().equals(TEST_USB_IFNAME)),
+                eq(IControlsTethering.STATE_TETHERED));
+
+        for (TetherInterfaceStateMachine tism :
+                mTetheringDependencies.ipv6CoordinatorNotifyList) {
+            NetworkState ipv6OnlyState = buildMobileUpstreamState(false, true, false);
+            tism.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0,
+                    upstreamState.linkProperties.isIPv6Provisioned()
+                            ? ipv6OnlyState.linkProperties
+                            : null);
+        }
+        mLooper.dispatchAll();
+    }
+
+    private void runUsbTethering(NetworkState upstreamState) {
+        prepareUsbTethering(upstreamState);
+        sendUsbBroadcast(true, true, true);
+        mLooper.dispatchAll();
+    }
+
+    @Test
+    public void workingMobileUsbTethering_IPv4() throws Exception {
+        NetworkState upstreamState = buildMobileIPv4UpstreamState();
+        runUsbTethering(upstreamState);
+
+        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+
+        sendIPv6TetherUpdates(upstreamState);
+        verify(mRouterAdvertisementDaemon, never()).buildNewRa(any(), notNull());
+    }
+
+    @Test
+    public void workingMobileUsbTethering_IPv6() throws Exception {
+        NetworkState upstreamState = buildMobileIPv6UpstreamState();
+        runUsbTethering(upstreamState);
+
+        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+
+        sendIPv6TetherUpdates(upstreamState);
+        verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
+        verify(mNetd, times(1)).tetherApplyDnsInterfaces();
+    }
+
+    @Test
+    public void workingMobileUsbTethering_DualStack() throws Exception {
+        NetworkState upstreamState = buildMobileDualStackUpstreamState();
+        runUsbTethering(upstreamState);
+
+        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+        verify(mRouterAdvertisementDaemon, times(1)).start();
+
+        sendIPv6TetherUpdates(upstreamState);
+        verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
+        verify(mNetd, times(1)).tetherApplyDnsInterfaces();
+    }
+
+    @Test
+    public void workingMobileUsbTethering_MultipleUpstreams() throws Exception {
+        NetworkState upstreamState = buildMobile464xlatUpstreamState();
+        runUsbTethering(upstreamState);
+
+        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
+        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME,
+                TEST_XLAT_MOBILE_IFNAME);
+
+        sendIPv6TetherUpdates(upstreamState);
+        verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
+        verify(mNetd, times(1)).tetherApplyDnsInterfaces();
+    }
+
+    @Test
+    public void workingMobileUsbTethering_v6Then464xlat() throws Exception {
+        // Setup IPv6
+        NetworkState upstreamState = buildMobileIPv6UpstreamState();
+        runUsbTethering(upstreamState);
+
+        // Then 464xlat comes up
+        upstreamState = buildMobile464xlatUpstreamState();
+        when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
+                .thenReturn(upstreamState);
+
+        // Upstream LinkProperties changed: UpstreamNetworkMonitor sends EVENT_ON_LINKPROPERTIES.
+        mTetheringDependencies.upstreamNetworkMonitorMasterSM.sendMessage(
+                Tethering.TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
+                UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES,
+                0,
+                upstreamState);
+        mLooper.dispatchAll();
+
+        // Forwarding is added for 464xlat, and was still added only once for v6
+        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
+        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME,
+                TEST_XLAT_MOBILE_IFNAME);
     }
 
     @Test
@@ -420,12 +662,12 @@
         // Emulate externally-visible WifiManager effects, causing the
         // per-interface state machine to start up, and telling us that
         // tethering mode is to be started.
-        mTethering.interfaceStatusChanged(mTestIfname, true);
+        mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
         sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
         mLooper.dispatchAll();
 
         verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
-        verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+        verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
         verifyNoMoreInteractions(mConnectivityManager);
         verifyNoMoreInteractions(mNMService);
         verifyNoMoreInteractions(mWifiManager);
@@ -448,30 +690,23 @@
         // Emulate externally-visible WifiManager effects, causing the
         // per-interface state machine to start up, and telling us that
         // tethering mode is to be started.
-        mTethering.interfaceStatusChanged(mTestIfname, true);
-        sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, mTestIfname, IFACE_IP_MODE_TETHERED);
+        mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
+        sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
         mLooper.dispatchAll();
 
         verifyInterfaceServingModeStarted();
-        verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+        verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
         verify(mNMService, times(1)).setIpForwardingEnabled(true);
         verify(mNMService, times(1)).startTethering(any(String[].class));
         verifyNoMoreInteractions(mNMService);
         verify(mWifiManager).updateInterfaceIpState(
-                mTestIfname, WifiManager.IFACE_IP_MODE_TETHERED);
+                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
         verifyNoMoreInteractions(mWifiManager);
-        verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_TETHER);
-        // UpstreamNetworkMonitor will be started, and will register two callbacks:
-        // a "listen all" and a "track default".
-        verify(mConnectivityManager, times(1)).registerNetworkCallback(
-                any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
-        verify(mConnectivityManager, times(1)).registerDefaultNetworkCallback(
-                any(NetworkCallback.class), any(Handler.class));
+        verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_ACTIVE_TETHER);
+        verify(mUpstreamNetworkMonitor, times(1)).start();
         // In tethering mode, in the default configuration, an explicit request
         // for a mobile network is also made.
-        verify(mConnectivityManager, times(1)).requestNetwork(
-                any(NetworkRequest.class), any(NetworkCallback.class), eq(0), anyInt(),
-                any(Handler.class));
+        verify(mUpstreamNetworkMonitor, times(1)).registerMobileNetworkRequest();
         // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
         verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
         verifyNoMoreInteractions(mConnectivityManager);
@@ -494,14 +729,14 @@
         // Emulate externally-visible WifiManager effects, when tethering mode
         // is being torn down.
         sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
-        mTethering.interfaceRemoved(mTestIfname);
+        mTethering.interfaceRemoved(TEST_WLAN_IFNAME);
         mLooper.dispatchAll();
 
-        verify(mNMService, times(1)).untetherInterface(mTestIfname);
+        verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
         // TODO: Why is {g,s}etInterfaceConfig() called more than once?
-        verify(mNMService, atLeastOnce()).getInterfaceConfig(mTestIfname);
+        verify(mNMService, atLeastOnce()).getInterfaceConfig(TEST_WLAN_IFNAME);
         verify(mNMService, atLeastOnce())
-                .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
+                .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
         verify(mNMService, times(1)).stopTethering();
         verify(mNMService, times(1)).setIpForwardingEnabled(false);
         verifyNoMoreInteractions(mNMService);
@@ -509,7 +744,7 @@
         // Asking for the last error after the per-interface state machine
         // has been reaped yields an unknown interface error.
         assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
-                mTethering.getLastTetherError(mTestIfname));
+                mTethering.getLastTetherError(TEST_WLAN_IFNAME));
     }
 
     // TODO: Test with and without interfaceStatusChanged().
@@ -530,21 +765,21 @@
         // Emulate externally-visible WifiManager effects, causing the
         // per-interface state machine to start up, and telling us that
         // tethering mode is to be started.
-        mTethering.interfaceStatusChanged(mTestIfname, true);
-        sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, mTestIfname, IFACE_IP_MODE_TETHERED);
+        mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
+        sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
         mLooper.dispatchAll();
 
         // We verify get/set called twice here: once for setup and once during
         // teardown because all events happen over the course of the single
         // dispatchAll() above.
-        verify(mNMService, times(2)).getInterfaceConfig(mTestIfname);
+        verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME);
         verify(mNMService, times(2))
-                .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
-        verify(mNMService, times(1)).tetherInterface(mTestIfname);
+                .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
+        verify(mNMService, times(1)).tetherInterface(TEST_WLAN_IFNAME);
         verify(mWifiManager).updateInterfaceIpState(
-                mTestIfname, WifiManager.IFACE_IP_MODE_TETHERED);
+                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
         verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
-        verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+        verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
         // This is called, but will throw.
         verify(mNMService, times(1)).setIpForwardingEnabled(true);
         // This never gets called because of the exception thrown above.
@@ -552,9 +787,9 @@
         // When the master state machine transitions to an error state it tells
         // downstream interfaces, which causes us to tell Wi-Fi about the error
         // so it can take down AP mode.
-        verify(mNMService, times(1)).untetherInterface(mTestIfname);
+        verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
         verify(mWifiManager).updateInterfaceIpState(
-                mTestIfname, WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR);
+                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR);
 
         verifyNoMoreInteractions(mWifiManager);
         verifyNoMoreInteractions(mConnectivityManager);
@@ -596,7 +831,7 @@
 
     @Test
     public void testDisallowTetheringWhenAtLeastOneTetheringInterfaceIsActive() throws Exception {
-        final String[] nonEmptyActiveIfacesList = new String[]{mTestIfname};
+        final String[] nonEmptyActiveIfacesList = new String[]{TEST_WLAN_IFNAME};
         final boolean currDisallow = false;
         final boolean nextDisallow = true;
         final int expectedInteractionsWithShowNotification = 1;
@@ -618,7 +853,7 @@
 
     @Test
     public void testAllowTetheringWhenAtLeastOneTetheringInterfaceIsActive() throws Exception {
-        final String[] nonEmptyActiveIfacesList = new String[]{mTestIfname};
+        final String[] nonEmptyActiveIfacesList = new String[]{TEST_WLAN_IFNAME};
         final boolean currDisallow = true;
         final boolean nextDisallow = false;
         final int expectedInteractionsWithShowNotification = 0;
@@ -629,7 +864,7 @@
 
     @Test
     public void testDisallowTetheringUnchanged() throws Exception {
-        final String[] nonEmptyActiveIfacesList = new String[]{mTestIfname};
+        final String[] nonEmptyActiveIfacesList = new String[]{TEST_WLAN_IFNAME};
         final int expectedInteractionsWithShowNotification = 0;
         boolean currDisallow = true;
         boolean nextDisallow = true;
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index f59850d..e377a47 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -70,6 +70,7 @@
 import android.os.Bundle;
 import android.os.INetworkManagementService;
 import android.os.Looper;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.support.test.filters.SmallTest;
@@ -88,6 +89,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.net.Inet4Address;
+import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -639,4 +642,32 @@
         lp.addRoute(new RouteInfo(new IpPrefix("::/1")));
         assertTrue(Vpn.providesRoutesToMostDestinations(lp));
     }
+
+    @Test
+    public void testDoesNotLockUpWithTooManyRoutes() {
+        final LinkProperties lp = new LinkProperties();
+        final byte[] ad = new byte[4];
+        // Actually evaluating this many routes under 1500ms is impossible on
+        // current hardware and for some time, as the algorithm is O(n²).
+        // Make sure the system has a safeguard against this and does not
+        // lock up.
+        final int MAX_ROUTES = 4000;
+        final long MAX_ALLOWED_TIME_MS = 1500;
+        for (int i = 0; i < MAX_ROUTES; ++i) {
+            ad[0] = (byte)((i >> 24) & 0xFF);
+            ad[1] = (byte)((i >> 16) & 0xFF);
+            ad[2] = (byte)((i >> 8) & 0xFF);
+            ad[3] = (byte)(i & 0xFF);
+            try {
+                lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.getByAddress(ad), 32)));
+            } catch (UnknownHostException e) {
+                // UnknownHostException is only thrown for an address of illegal length,
+                // which can't happen in the case above.
+            }
+        }
+        final long start = SystemClock.currentThreadTimeMillis();
+        assertTrue(Vpn.providesRoutesToMostDestinations(lp));
+        final long end = SystemClock.currentThreadTimeMillis();
+        assertTrue(end - start < MAX_ALLOWED_TIME_MS);
+    }
 }
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
index db5373a..7c77cf5 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
@@ -31,7 +31,6 @@
 import static android.net.ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
 import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
 import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
 import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
 import static android.net.ConnectivityManager.TETHERING_USB;
 import static android.net.ConnectivityManager.TETHERING_WIFI;
@@ -39,12 +38,12 @@
 import static com.android.server.connectivity.tethering.IControlsTethering.STATE_TETHERED;
 import static com.android.server.connectivity.tethering.IControlsTethering.STATE_UNAVAILABLE;
 
-import android.net.ConnectivityManager;
 import android.net.INetworkStatsService;
 import android.net.InterfaceConfiguration;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.RouteInfo;
+import android.net.util.InterfaceSet;
 import android.net.util.SharedLog;
 import android.os.INetworkManagementService;
 import android.os.RemoteException;
@@ -75,6 +74,7 @@
     @Mock private IControlsTethering mTetherHelper;
     @Mock private InterfaceConfiguration mInterfaceConfiguration;
     @Mock private SharedLog mSharedLog;
+    @Mock private TetheringDependencies mTetheringDependencies;
 
     private final TestLooper mLooper = new TestLooper();
     private final ArgumentCaptor<LinkProperties> mLinkPropertiesCaptor =
@@ -84,7 +84,7 @@
     private void initStateMachine(int interfaceType) throws Exception {
         mTestedSm = new TetherInterfaceStateMachine(
                 IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog,
-                mNMService, mStatsService, mTetherHelper);
+                mNMService, mStatsService, mTetherHelper, mTetheringDependencies);
         mTestedSm.start();
         // Starting the state machine always puts us in a consistent state and notifies
         // the rest of the world that we've changed from an unknown to available state.
@@ -111,7 +111,8 @@
     @Test
     public void startsOutAvailable() {
         mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(),
-                TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mTetherHelper);
+                TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mTetherHelper,
+                mTetheringDependencies);
         mTestedSm.start();
         mLooper.dispatchAll();
         verify(mTetherHelper).updateInterfaceState(
@@ -346,7 +347,7 @@
      * Send a command to the state machine under test, and run the event loop to idle.
      *
      * @param command One of the TetherInterfaceStateMachine.CMD_* constants.
-     * @param obj An additional argument to pass.
+     * @param arg1 An additional argument to pass.
      */
     private void dispatchCommand(int command, int arg1) {
         mTestedSm.sendMessage(command, arg1);
@@ -371,7 +372,7 @@
      */
     private void dispatchTetherConnectionChanged(String upstreamIface) {
         mTestedSm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
-                upstreamIface);
+                new InterfaceSet(upstreamIface));
         mLooper.dispatchAll();
     }
 
diff --git a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
index c3b9def..9661dc2 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
@@ -147,6 +147,16 @@
     }
 
     @Test
+    public void testCallbacksRegistered() {
+        mUNM.start();
+        verify(mCM, times(1)).registerNetworkCallback(any(), any(), any());
+        verify(mCM, times(1)).registerDefaultNetworkCallback(any(), any());
+
+        mUNM.stop();
+        verify(mCM, times(2)).unregisterNetworkCallback(any(NetworkCallback.class));
+    }
+
+    @Test
     public void testRequestsMobileNetwork() throws Exception {
         assertFalse(mUNM.mobileNetworkRequested());
         assertEquals(0, mCM.requested.size());
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 300c701..499f254 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -211,7 +211,7 @@
         signature != atoms.signatures.end(); signature++) {
         int argIndex;
 
-        fprintf(out, "void\n");
+        fprintf(out, "int\n");
         fprintf(out, "stats_write(int32_t code");
         argIndex = 1;
         for (vector<java_type_t>::const_iterator arg = signature->begin();
@@ -251,7 +251,7 @@
                             " diff length: %s vs %s\");\n",
                             attributionDecl.fields.front().name.c_str(),
                             chainField.name.c_str());
-                        fprintf(out, "        return;\n");
+                        fprintf(out, "        return -EINVAL;\n");
                         fprintf(out, "    }\n");
                     }
                 }
@@ -284,7 +284,7 @@
             argIndex++;
         }
 
-        fprintf(out, "    event.write(LOG_ID_STATS);\n");
+        fprintf(out, "    return event.write(LOG_ID_STATS);\n");
         fprintf(out, "}\n");
         fprintf(out, "\n");
     }
@@ -293,7 +293,7 @@
         signature != atoms.non_chained_signatures.end(); signature++) {
         int argIndex;
 
-        fprintf(out, "void\n");
+        fprintf(out, "int\n");
         fprintf(out, "stats_write_non_chained(int32_t code");
         argIndex = 1;
         for (vector<java_type_t>::const_iterator arg = signature->begin();
@@ -327,7 +327,7 @@
             argIndex++;
         }
 
-        fprintf(out, "    event.write(LOG_ID_STATS);\n");
+        fprintf(out, "    return event.write(LOG_ID_STATS);\n");
         fprintf(out, "}\n");
         fprintf(out, "\n");
     }
@@ -377,7 +377,7 @@
     const AtomDecl &attributionDecl) {
     for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
             signature != signatures.end(); signature++) {
-        fprintf(out, "void %s(int32_t code ", method_name.c_str());
+        fprintf(out, "int %s(int32_t code ", method_name.c_str());
         int argIndex = 1;
         for (vector<java_type_t>::const_iterator arg = signature->begin();
             arg != signature->end(); arg++) {
@@ -522,7 +522,7 @@
     const AtomDecl &attributionDecl) {
     for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
         signature != signatures.end(); signature++) {
-        fprintf(out, "    public static native void %s(int code", method_name.c_str());
+        fprintf(out, "    public static native int %s(int code", method_name.c_str());
         int argIndex = 1;
         for (vector<java_type_t>::const_iterator arg = signature->begin();
             arg != signature->end(); arg++) {
@@ -719,7 +719,7 @@
             result += java_type_signature(*arg);
         }
     }
-    result += ")V";
+    result += ")I";
     return result;
 }
 
@@ -732,7 +732,7 @@
         signature != signatures.end(); signature++) {
         int argIndex;
 
-        fprintf(out, "static void\n");
+        fprintf(out, "static int\n");
         fprintf(out, "%s(JNIEnv* env, jobject clazz UNUSED, jint code",
                 jni_function_name(java_method_name, *signature).c_str());
         argIndex = 1;
@@ -779,7 +779,7 @@
                             "\"java/lang/IllegalArgumentException\", "
                             "\"invalid attribution field(%s) length.\");\n",
                             chainField.name.c_str());
-                        fprintf(out, "        return;\n");
+                        fprintf(out, "        return -EINVAL;\n");
                         fprintf(out, "    }\n");
                     }
                     if (chainField.javaType == JAVA_TYPE_INT) {
@@ -822,7 +822,7 @@
 
         // stats_write call
         argIndex = 1;
-        fprintf(out, "    android::util::%s(code", cpp_method_name.c_str());
+        fprintf(out, "   int ret =  android::util::%s(code", cpp_method_name.c_str());
         for (vector<java_type_t>::const_iterator arg = signature->begin();
                 arg != signature->end(); arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
@@ -868,6 +868,7 @@
             }
             argIndex++;
         }
+        fprintf(out, "    return ret;\n");
 
         fprintf(out, "}\n");
         fprintf(out, "\n");
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 21ae3a9..b77b1ad 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -25,11 +25,13 @@
 import android.net.ProxyInfo;
 import android.net.StaticIpConfiguration;
 import android.net.Uri;
+import android.net.wifi.WifiInfo;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.BackupUtils;
+import android.util.Log;
 
 import java.io.ByteArrayOutputStream;
 import java.io.DataInputStream;
@@ -76,6 +78,8 @@
 
     /** {@hide} */
     private String mPasspointManagementObjectTree;
+    /** {@hide} */
+    private static final int MAXIMUM_RANDOM_MAC_GENERATION_RETRY = 3;
 
     /**
      * Recognized key management schemes.
@@ -798,27 +802,37 @@
      * @hide
      * Randomized MAC address to use with this particular network
      */
+    @NonNull
     private MacAddress mRandomizedMacAddress;
 
     /**
      * @hide
      * Checks if the given MAC address can be used for Connected Mac Randomization
-     * by verifying that it is non-null, unicast, and locally assigned.
+     * by verifying that it is non-null, unicast, locally assigned, and not default mac.
      * @param mac MacAddress to check
      * @return true if mac is good to use
      */
-    private boolean isValidMacAddressForRandomization(MacAddress mac) {
-        return mac != null && !mac.isMulticastAddress() && mac.isLocallyAssigned();
+    public static boolean isValidMacAddressForRandomization(MacAddress mac) {
+        return mac != null && !mac.isMulticastAddress() && mac.isLocallyAssigned()
+                && !MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS).equals(mac);
     }
 
     /**
      * @hide
      * Returns Randomized MAC address to use with the network.
-     * If it is not set/valid, create a new randomized address.
+     * If it is not set/valid, creates a new randomized address.
+     * If it can't generate a valid mac, returns the default MAC.
      */
-    public MacAddress getOrCreateRandomizedMacAddress() {
-        if (!isValidMacAddressForRandomization(mRandomizedMacAddress)) {
+    public @NonNull MacAddress getOrCreateRandomizedMacAddress() {
+        int randomMacGenerationCount = 0;
+        while (!isValidMacAddressForRandomization(mRandomizedMacAddress)
+                && randomMacGenerationCount < MAXIMUM_RANDOM_MAC_GENERATION_RETRY) {
             mRandomizedMacAddress = MacAddress.createRandomUnicastAddress();
+            randomMacGenerationCount++;
+        }
+
+        if (!isValidMacAddressForRandomization(mRandomizedMacAddress)) {
+            mRandomizedMacAddress = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
         }
         return mRandomizedMacAddress;
     }
@@ -828,10 +842,7 @@
      * Returns MAC address set to be the local randomized MAC address.
      * Does not guarantee that the returned address is valid for use.
      */
-    public MacAddress getRandomizedMacAddress() {
-        if (mRandomizedMacAddress == null) {
-            mRandomizedMacAddress = MacAddress.ALL_ZEROS_ADDRESS;
-        }
+    public @NonNull MacAddress getRandomizedMacAddress() {
         return mRandomizedMacAddress;
     }
 
@@ -839,7 +850,11 @@
      * @hide
      * @param mac MacAddress to change into
      */
-    public void setRandomizedMacAddress(MacAddress mac) {
+    public void setRandomizedMacAddress(@NonNull MacAddress mac) {
+        if (mac == null) {
+            Log.e(TAG, "setRandomizedMacAddress received null MacAddress.");
+            return;
+        }
         mRandomizedMacAddress = mac;
     }
 
@@ -1532,7 +1547,7 @@
         creatorUid = -1;
         shared = true;
         dtimInterval = 0;
-        mRandomizedMacAddress = MacAddress.ALL_ZEROS_ADDRESS;
+        mRandomizedMacAddress = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
     }
 
     /**
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index c8df087..433285b 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1317,6 +1317,7 @@
         if (pin) {
             NetworkRequest request = new NetworkRequest.Builder()
                     .clearCapabilities()
+                    .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
                     .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                     .build();
             NetworkPinner.pin(mContext, request);
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 8a3a7f5..3517984 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -18,12 +18,14 @@
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.assertFalse;
 
 import android.os.Parcel;
 import android.net.MacAddress;
 import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
+import android.net.wifi.WifiInfo;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -176,22 +178,25 @@
     @Test
     public void testGetOrCreateRandomizedMacAddress_SavesAndReturnsSameAddress() {
         WifiConfiguration config = new WifiConfiguration();
-        assertEquals(MacAddress.ALL_ZEROS_ADDRESS, config.getRandomizedMacAddress());
+        MacAddress defaultMac = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
+        assertEquals(defaultMac, config.getRandomizedMacAddress());
 
         MacAddress firstMacAddress = config.getOrCreateRandomizedMacAddress();
         MacAddress secondMacAddress = config.getOrCreateRandomizedMacAddress();
 
+        assertNotEquals(defaultMac, firstMacAddress);
         assertEquals(firstMacAddress, secondMacAddress);
     }
 
     @Test
     public void testSetRandomizedMacAddress_ChangesSavedAddress() {
         WifiConfiguration config = new WifiConfiguration();
-        assertEquals(MacAddress.ALL_ZEROS_ADDRESS, config.getRandomizedMacAddress());
+        MacAddress defaultMac = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
+        assertEquals(defaultMac, config.getRandomizedMacAddress());
 
         MacAddress macToChangeInto = MacAddress.createRandomUnicastAddress();
         config.setRandomizedMacAddress(macToChangeInto);
-        MacAddress macAfterChange = config.getOrCreateRandomizedMacAddress();
+        MacAddress macAfterChange = config.getRandomizedMacAddress();
 
         assertEquals(macToChangeInto, macAfterChange);
     }
@@ -200,24 +205,37 @@
     public void testGetOrCreateRandomizedMacAddress_ReRandomizesInvalidAddress() {
         WifiConfiguration config =  new WifiConfiguration();
 
+        MacAddress defaultMac = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
         MacAddress macAddressZeroes = MacAddress.ALL_ZEROS_ADDRESS;
         MacAddress macAddressMulticast = MacAddress.fromString("03:ff:ff:ff:ff:ff");
         MacAddress macAddressGlobal = MacAddress.fromString("fc:ff:ff:ff:ff:ff");
 
         config.setRandomizedMacAddress(null);
         MacAddress macAfterChange = config.getOrCreateRandomizedMacAddress();
-        assertFalse(macAfterChange.equals(null));
+        assertNotEquals(macAfterChange, null);
+
+        config.setRandomizedMacAddress(defaultMac);
+        macAfterChange = config.getOrCreateRandomizedMacAddress();
+        assertNotEquals(macAfterChange, defaultMac);
 
         config.setRandomizedMacAddress(macAddressZeroes);
         macAfterChange = config.getOrCreateRandomizedMacAddress();
-        assertFalse(macAfterChange.equals(macAddressZeroes));
+        assertNotEquals(macAfterChange, macAddressZeroes);
 
         config.setRandomizedMacAddress(macAddressMulticast);
         macAfterChange = config.getOrCreateRandomizedMacAddress();
-        assertFalse(macAfterChange.equals(macAddressMulticast));
+        assertNotEquals(macAfterChange, macAddressMulticast);
 
         config.setRandomizedMacAddress(macAddressGlobal);
         macAfterChange = config.getOrCreateRandomizedMacAddress();
-        assertFalse(macAfterChange.equals(macAddressGlobal));
+        assertNotEquals(macAfterChange, macAddressGlobal);
+    }
+
+    @Test
+    public void testSetRandomizedMacAddress_DoesNothingWhenNull() {
+        WifiConfiguration config = new WifiConfiguration();
+        MacAddress defaultMac = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
+        config.setRandomizedMacAddress(null);
+        assertEquals(defaultMac, config.getRandomizedMacAddress());
     }
 }