Merge "Canonicalize default ringtones." into qt-dev
diff --git a/api/current.txt b/api/current.txt
index feb0bb6..6957161 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5485,7 +5485,8 @@
     method @NonNull public android.graphics.drawable.Icon getIcon();
     method @NonNull public android.app.PendingIntent getIntent();
     method @Deprecated public boolean getSuppressInitialNotification();
-    method public boolean getSuppressNotification();
+    method @Deprecated public boolean getSuppressNotification();
+    method public boolean isNotificationSuppressed();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification.BubbleMetadata> CREATOR;
   }
@@ -38514,7 +38515,6 @@
     field public static final String DISPLAY_NAME = "_display_name";
     field public static final String DOCUMENT_ID = "document_id";
     field public static final String DURATION = "duration";
-    field public static final String GROUP_ID = "group_id";
     field public static final String HEIGHT = "height";
     field public static final String INSTANCE_ID = "instance_id";
     field public static final String IS_PENDING = "is_pending";
diff --git a/api/removed.txt b/api/removed.txt
index 8836326..ab5e7e5 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -539,6 +539,7 @@
   }
 
   public static interface MediaStore.MediaColumns extends android.provider.BaseColumns {
+    field @Deprecated public static final String GROUP_ID = "group_id";
     field @Deprecated public static final String HASH = "_hash";
     field @Deprecated public static final String IS_TRASHED = "is_trashed";
     field @Deprecated public static final String PRIMARY_DIRECTORY = "primary_directory";
diff --git a/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl b/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
index 4a66715..cd474c0 100644
--- a/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
+++ b/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
@@ -25,6 +25,8 @@
   const int POLICY_VENDOR_PARTITION = 0x00000004;
   const int POLICY_PRODUCT_PARTITION = 0x00000008;
   const int POLICY_SIGNATURE = 0x00000010;
+  const int POLICY_ODM_PARTITION = 0x00000020;
+  const int POLICY_OEM_PARTITION = 0x00000040;
 
   @utf8InCpp String getIdmapPath(@utf8InCpp String overlayApkPath, int userId);
   boolean removeIdmap(@utf8InCpp String overlayApkPath, int userId);
diff --git a/cmds/idmap2/include/idmap2/Policies.h b/cmds/idmap2/include/idmap2/Policies.h
index 90c698c..87edd35 100644
--- a/cmds/idmap2/include/idmap2/Policies.h
+++ b/cmds/idmap2/include/idmap2/Policies.h
@@ -26,11 +26,13 @@
 
 namespace android::idmap2 {
 
-constexpr const char* kPolicyPublic = "public";
+constexpr const char* kPolicyOdm = "odm";
+constexpr const char* kPolicyOem = "oem";
 constexpr const char* kPolicyProduct = "product";
+constexpr const char* kPolicyPublic = "public";
+constexpr const char* kPolicySignature = "signature";
 constexpr const char* kPolicySystem = "system";
 constexpr const char* kPolicyVendor = "vendor";
-constexpr const char* kPolicySignature = "signature";
 
 using PolicyFlags = ResTable_overlayable_policy_header::PolicyFlags;
 using PolicyBitmask = uint32_t;
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index aec1a6f..4649675 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -282,6 +282,7 @@
                               const utils::OverlayManifestInfo& overlay_info,
                               const PolicyBitmask& fulfilled_policies, const ResourceId& resid) {
   static constexpr const PolicyBitmask sDefaultPolicies =
+      PolicyFlags::POLICY_ODM_PARTITION | PolicyFlags::POLICY_OEM_PARTITION |
       PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION |
       PolicyFlags::POLICY_PRODUCT_PARTITION | PolicyFlags::POLICY_SIGNATURE;
 
diff --git a/cmds/idmap2/libidmap2/Policies.cpp b/cmds/idmap2/libidmap2/Policies.cpp
index 0a0cecf..495fe61 100644
--- a/cmds/idmap2/libidmap2/Policies.cpp
+++ b/cmds/idmap2/libidmap2/Policies.cpp
@@ -17,8 +17,8 @@
 #include "idmap2/Policies.h"
 
 #include <iterator>
-#include <map>
 #include <string>
+#include <unordered_map>
 #include <vector>
 
 #include "androidfw/ResourceTypes.h"
@@ -27,19 +27,17 @@
 
 namespace android::idmap2 {
 
-namespace {
-
-const std::map<android::StringPiece, PolicyFlags> kStringToFlag = {
-    {kPolicyPublic, PolicyFlags::POLICY_PUBLIC},
-    {kPolicyProduct, PolicyFlags::POLICY_PRODUCT_PARTITION},
-    {kPolicySystem, PolicyFlags::POLICY_SYSTEM_PARTITION},
-    {kPolicyVendor, PolicyFlags::POLICY_VENDOR_PARTITION},
-    {kPolicySignature, PolicyFlags::POLICY_SIGNATURE},
-};
-
-}  // namespace
-
 Result<PolicyBitmask> PoliciesToBitmask(const std::vector<std::string>& policies) {
+  static const std::unordered_map<android::StringPiece, PolicyFlags> kStringToFlag = {
+      {kPolicyOdm, PolicyFlags::POLICY_ODM_PARTITION},
+      {kPolicyOem, PolicyFlags::POLICY_OEM_PARTITION},
+      {kPolicyPublic, PolicyFlags::POLICY_PUBLIC},
+      {kPolicyProduct, PolicyFlags::POLICY_PRODUCT_PARTITION},
+      {kPolicySignature, PolicyFlags::POLICY_SIGNATURE},
+      {kPolicySystem, PolicyFlags::POLICY_SYSTEM_PARTITION},
+      {kPolicyVendor, PolicyFlags::POLICY_VENDOR_PARTITION},
+  };
+
   PolicyBitmask bitmask = 0;
   for (const std::string& policy : policies) {
     const auto iter = kStringToFlag.find(policy);
@@ -55,6 +53,15 @@
 
 std::vector<std::string> BitmaskToPolicies(const PolicyBitmask& bitmask) {
   std::vector<std::string> policies;
+
+  if ((bitmask & PolicyFlags::POLICY_ODM_PARTITION) != 0) {
+    policies.emplace_back(kPolicyOdm);
+  }
+
+  if ((bitmask & PolicyFlags::POLICY_OEM_PARTITION) != 0) {
+    policies.emplace_back(kPolicyOem);
+  }
+
   if ((bitmask & PolicyFlags::POLICY_PUBLIC) != 0) {
     policies.emplace_back(kPolicyPublic);
   }
@@ -63,6 +70,10 @@
     policies.emplace_back(kPolicyProduct);
   }
 
+  if ((bitmask & PolicyFlags::POLICY_SIGNATURE) != 0) {
+    policies.emplace_back(kPolicySignature);
+  }
+
   if ((bitmask & PolicyFlags::POLICY_SYSTEM_PARTITION) != 0) {
     policies.emplace_back(kPolicySystem);
   }
@@ -71,10 +82,6 @@
     policies.emplace_back(kPolicyVendor);
   }
 
-  if ((bitmask & PolicyFlags::POLICY_SIGNATURE) != 0) {
-    policies.emplace_back(kPolicySignature);
-  }
-
   return policies;
 }
 
diff --git a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
index 9cdc86c..9348ab7 100644
--- a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
+++ b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
@@ -109,49 +109,55 @@
   success = LoadedIdmap::Lookup(header, 0x0002, &entry);  // string/c
   ASSERT_FALSE(success);
 
-  success = LoadedIdmap::Lookup(header, 0x0003, &entry);  // string/other
+  success = LoadedIdmap::Lookup(header, 0x0003, &entry);  // string/policy_odm
   ASSERT_FALSE(success);
 
-  success = LoadedIdmap::Lookup(header, 0x0004, &entry);  // string/not_overlayable
+  success = LoadedIdmap::Lookup(header, 0x0004, &entry);  // string/policy_oem
   ASSERT_FALSE(success);
 
-  success = LoadedIdmap::Lookup(header, 0x0005, &entry);  // string/policy_product
+  success = LoadedIdmap::Lookup(header, 0x0005, &entry);  // string/other
   ASSERT_FALSE(success);
 
-  success = LoadedIdmap::Lookup(header, 0x0006, &entry);  // string/policy_public
+  success = LoadedIdmap::Lookup(header, 0x0006, &entry);  // string/not_overlayable
   ASSERT_FALSE(success);
 
-  success = LoadedIdmap::Lookup(header, 0x0007, &entry);  // string/policy_system
+  success = LoadedIdmap::Lookup(header, 0x0007, &entry);  // string/policy_product
   ASSERT_FALSE(success);
 
-  success = LoadedIdmap::Lookup(header, 0x0008, &entry);  // string/policy_system_vendor
+  success = LoadedIdmap::Lookup(header, 0x0008, &entry);  // string/policy_public
   ASSERT_FALSE(success);
 
-  success = LoadedIdmap::Lookup(header, 0x0009, &entry);  // string/policy_signature
+  success = LoadedIdmap::Lookup(header, 0x0009, &entry);  // string/policy_system
   ASSERT_FALSE(success);
 
-  success = LoadedIdmap::Lookup(header, 0x000a, &entry);  // string/str1
+  success = LoadedIdmap::Lookup(header, 0x000a, &entry);  // string/policy_system_vendor
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x000b, &entry);  // string/policy_signature
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x000c, &entry);  // string/str1
   ASSERT_TRUE(success);
   ASSERT_EQ(entry, 0x0000);
 
-  success = LoadedIdmap::Lookup(header, 0x000b, &entry);  // string/str2
+  success = LoadedIdmap::Lookup(header, 0x000d, &entry);  // string/str2
   ASSERT_FALSE(success);
 
-  success = LoadedIdmap::Lookup(header, 0x000c, &entry);  // string/str3
+  success = LoadedIdmap::Lookup(header, 0x000e, &entry);  // string/str3
   ASSERT_TRUE(success);
   ASSERT_EQ(entry, 0x0001);
 
-  success = LoadedIdmap::Lookup(header, 0x000d, &entry);  // string/str4
+  success = LoadedIdmap::Lookup(header, 0x000f, &entry);  // string/str4
   ASSERT_TRUE(success);
   ASSERT_EQ(entry, 0x0002);
 
-  success = LoadedIdmap::Lookup(header, 0x000e, &entry);  // string/x
+  success = LoadedIdmap::Lookup(header, 0x0010, &entry);  // string/x
   ASSERT_FALSE(success);
 
-  success = LoadedIdmap::Lookup(header, 0x000f, &entry);  // string/y
+  success = LoadedIdmap::Lookup(header, 0x0011, &entry);  // string/y
   ASSERT_FALSE(success);
 
-  success = LoadedIdmap::Lookup(header, 0x0010, &entry);  // string/z
+  success = LoadedIdmap::Lookup(header, 0x0012, &entry);  // string/z
   ASSERT_FALSE(success);
 }
 
diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
index c18744c..8a48f4b 100644
--- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp
+++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
@@ -128,9 +128,9 @@
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
   ASSERT_NE(result->stdout.find("0x7f010000 -> 0x7f010000 integer/int1"), std::string::npos);
-  ASSERT_NE(result->stdout.find("0x7f02000a -> 0x7f020000 string/str1"), std::string::npos);
-  ASSERT_NE(result->stdout.find("0x7f02000c -> 0x7f020001 string/str3"), std::string::npos);
-  ASSERT_NE(result->stdout.find("0x7f02000d -> 0x7f020002 string/str4"), std::string::npos);
+  ASSERT_NE(result->stdout.find("0x7f02000c -> 0x7f020000 string/str1"), std::string::npos);
+  ASSERT_NE(result->stdout.find("0x7f02000e -> 0x7f020001 string/str3"), std::string::npos);
+  ASSERT_NE(result->stdout.find("0x7f02000f -> 0x7f020002 string/str4"), std::string::npos);
   ASSERT_EQ(result->stdout.find("00000210:     007f  target package id"), std::string::npos);
 
   // clang-format off
@@ -299,7 +299,7 @@
                           "lookup",
                           "--idmap-path", GetIdmapPath(),
                           "--config", "",
-                          "--resid", "0x7f02000a"});  // string/str1
+                          "--resid", "0x7f02000c"});  // string/str1
   // clang-format on
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index 90fe9a7..0f47f1e 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -194,7 +194,7 @@
   ASSERT_THAT(idmap->GetHeader(), NotNull());
   ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
   ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x01U);
-  ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0xd513ca1b);
+  ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0x76a20829);
   ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0x8635c2ed);
   ASSERT_EQ(idmap->GetHeader()->GetTargetPath().to_string(), target_apk_path);
   ASSERT_EQ(idmap->GetHeader()->GetOverlayPath(), overlay_apk_path);
@@ -220,7 +220,7 @@
   ASSERT_EQ(types[1]->GetTargetTypeId(), 0x02U);
   ASSERT_EQ(types[1]->GetOverlayTypeId(), 0x02U);
   ASSERT_EQ(types[1]->GetEntryCount(), 4U);
-  ASSERT_EQ(types[1]->GetEntryOffset(), 10U);
+  ASSERT_EQ(types[1]->GetEntryOffset(), 12U);
   ASSERT_EQ(types[1]->GetEntry(0), 0x0000U);
   ASSERT_EQ(types[1]->GetEntry(1), kNoEntry);
   ASSERT_EQ(types[1]->GetEntry(2), 0x0001U);
@@ -251,7 +251,7 @@
   ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
   ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
   ASSERT_EQ(types[0]->GetEntryCount(), 4U);
-  ASSERT_EQ(types[0]->GetEntryOffset(), 6U);
+  ASSERT_EQ(types[0]->GetEntryOffset(), 8U);
   ASSERT_EQ(types[0]->GetEntry(0), 0x0000U);   // string/policy_public
   ASSERT_EQ(types[0]->GetEntry(1), kNoEntry);  // string/policy_signature
   ASSERT_EQ(types[0]->GetEntry(2), 0x0001U);   // string/policy_system
@@ -281,7 +281,7 @@
   ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
   ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
   ASSERT_EQ(types[0]->GetEntryCount(), 1U);
-  ASSERT_EQ(types[0]->GetEntryOffset(), 7U);
+  ASSERT_EQ(types[0]->GetEntryOffset(), 9U);
   ASSERT_EQ(types[0]->GetEntry(0), 0x0000U);  // string/policy_signature
 }
 
@@ -310,11 +310,11 @@
   ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
   ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
   ASSERT_EQ(types[0]->GetEntryCount(), 4U);
-  ASSERT_EQ(types[0]->GetEntryOffset(), 6U);
-  ASSERT_EQ(types[0]->GetEntry(0), 0x0003U);   // string/policy_public
+  ASSERT_EQ(types[0]->GetEntryOffset(), 8U);
+  ASSERT_EQ(types[0]->GetEntry(0), 0x0005U);   // string/policy_public
   ASSERT_EQ(types[0]->GetEntry(1), kNoEntry);  // string/policy_signature
-  ASSERT_EQ(types[0]->GetEntry(2), 0x0005U);   // string/policy_system
-  ASSERT_EQ(types[0]->GetEntry(3), 0x0006U);   // string/policy_system_vendor
+  ASSERT_EQ(types[0]->GetEntry(2), 0x0007U);   // string/policy_system
+  ASSERT_EQ(types[0]->GetEntry(3), 0x0008U);   // string/policy_system_vendor
 }
 
 // Overlays should ignore all overlayable restrictions if enforcement of overlayable is disabled.
@@ -341,15 +341,17 @@
 
   ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
   ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
-  ASSERT_EQ(types[0]->GetEntryCount(), 7U);
+  ASSERT_EQ(types[0]->GetEntryCount(), 9U);
   ASSERT_EQ(types[0]->GetEntryOffset(), 3U);
   ASSERT_EQ(types[0]->GetEntry(0), 0x0000U);  // string/not_overlayable
-  ASSERT_EQ(types[0]->GetEntry(1), 0x0001U);  // string/other
-  ASSERT_EQ(types[0]->GetEntry(2), 0x0002U);  // string/policy_product
-  ASSERT_EQ(types[0]->GetEntry(3), 0x0003U);  // string/policy_signature
-  ASSERT_EQ(types[0]->GetEntry(4), 0x0004U);  // string/policy_public
-  ASSERT_EQ(types[0]->GetEntry(5), 0x0005U);  // string/policy_system
-  ASSERT_EQ(types[0]->GetEntry(6), 0x0006U);  // string/policy_system_vendor
+  ASSERT_EQ(types[0]->GetEntry(1), 0x0001U);  // string/policy_odm
+  ASSERT_EQ(types[0]->GetEntry(2), 0x0002U);  // string/policy_oem
+  ASSERT_EQ(types[0]->GetEntry(3), 0x0003U);  // string/other
+  ASSERT_EQ(types[0]->GetEntry(4), 0x0004U);  // string/policy_product
+  ASSERT_EQ(types[0]->GetEntry(5), 0x0005U);  // string/policy_public
+  ASSERT_EQ(types[0]->GetEntry(6), 0x0006U);  // string/policy_signature
+  ASSERT_EQ(types[0]->GetEntry(7), 0x0007U);  // string/policy_system
+  ASSERT_EQ(types[0]->GetEntry(8), 0x0008U);  // string/policy_system_vendor
 }
 
 // Overlays that do not specify a target <overlayable> can overlay resources defined as overlayable.
@@ -381,7 +383,7 @@
   ASSERT_EQ(types[1]->GetTargetTypeId(), 0x02U);
   ASSERT_EQ(types[1]->GetOverlayTypeId(), 0x02U);
   ASSERT_EQ(types[1]->GetEntryCount(), 4U);
-  ASSERT_EQ(types[1]->GetEntryOffset(), 10U);
+  ASSERT_EQ(types[1]->GetEntryOffset(), 12U);
   ASSERT_EQ(types[1]->GetEntry(0), 0x0000U);   // string/str1
   ASSERT_EQ(types[1]->GetEntry(1), kNoEntry);  // string/str2
   ASSERT_EQ(types[1]->GetEntry(2), 0x0001U);   // string/str3
@@ -412,7 +414,6 @@
     ASSERT_EQ(dataBlocks.size(), 1U);
 
     const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
-
     ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
     ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U);
 
@@ -421,15 +422,17 @@
 
     ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
     ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
-    ASSERT_EQ(types[0]->GetEntryCount(), 7U);
+    ASSERT_EQ(types[0]->GetEntryCount(), 9U);
     ASSERT_EQ(types[0]->GetEntryOffset(), 3U);
     ASSERT_EQ(types[0]->GetEntry(0), 0x0000U);  // string/not_overlayable
-    ASSERT_EQ(types[0]->GetEntry(1), 0x0001U);  // string/other
-    ASSERT_EQ(types[0]->GetEntry(2), 0x0002U);  // string/policy_product
-    ASSERT_EQ(types[0]->GetEntry(3), 0x0003U);  // string/policy_public
-    ASSERT_EQ(types[0]->GetEntry(4), 0x0004U);  // string/string/policy_signature
-    ASSERT_EQ(types[0]->GetEntry(5), 0x0005U);  // string/policy_system
-    ASSERT_EQ(types[0]->GetEntry(6), 0x0006U);  // string/policy_system_vendor
+    ASSERT_EQ(types[0]->GetEntry(1), 0x0001U);  // string/policy_odm
+    ASSERT_EQ(types[0]->GetEntry(2), 0x0002U);  // string/policy_oem
+    ASSERT_EQ(types[0]->GetEntry(3), 0x0003U);  // string/other
+    ASSERT_EQ(types[0]->GetEntry(4), 0x0004U);  // string/policy_product
+    ASSERT_EQ(types[0]->GetEntry(5), 0x0005U);  // string/policy_public
+    ASSERT_EQ(types[0]->GetEntry(6), 0x0006U);  // string/policy_signature
+    ASSERT_EQ(types[0]->GetEntry(7), 0x0007U);  // string/policy_system
+    ASSERT_EQ(types[0]->GetEntry(8), 0x0008U);  // string/policy_system_vendor
   };
 
   CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_SIGNATURE,
@@ -451,6 +454,16 @@
               /* enforce_overlayable */ true, &idmap);
   ASSERT_THAT(idmap, NotNull());
   CheckEntries();
+
+  CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_ODM_PARTITION,
+              /* enforce_overlayable */ true, &idmap);
+  ASSERT_THAT(idmap, NotNull());
+  CheckEntries();
+
+  CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_OEM_PARTITION,
+              /* enforce_overlayable */ true, &idmap);
+  ASSERT_THAT(idmap, NotNull());
+  CheckEntries();
 }
 
 TEST(IdmapTests, FailToCreateIdmapFromApkAssetsIfPathTooLong) {
diff --git a/cmds/idmap2/tests/PoliciesTests.cpp b/cmds/idmap2/tests/PoliciesTests.cpp
index e30da76..eca7404 100644
--- a/cmds/idmap2/tests/PoliciesTests.cpp
+++ b/cmds/idmap2/tests/PoliciesTests.cpp
@@ -38,9 +38,10 @@
   ASSERT_TRUE(bitmask3);
   ASSERT_EQ(*bitmask3, PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION);
 
-  const auto bitmask4 = PoliciesToBitmask({"public", "product", "system", "vendor"});
+  const auto bitmask4 = PoliciesToBitmask({"odm", "oem", "public", "product", "system", "vendor"});
   ASSERT_TRUE(bitmask4);
-  ASSERT_EQ(*bitmask4, PolicyFlags::POLICY_PUBLIC | PolicyFlags::POLICY_PRODUCT_PARTITION |
+  ASSERT_EQ(*bitmask4, PolicyFlags::POLICY_ODM_PARTITION | PolicyFlags::POLICY_OEM_PARTITION |
+                           PolicyFlags::POLICY_PUBLIC | PolicyFlags::POLICY_PRODUCT_PARTITION |
                            PolicyFlags::POLICY_SYSTEM_PARTITION |
                            PolicyFlags::POLICY_VENDOR_PARTITION);
 
@@ -64,4 +65,28 @@
   ASSERT_FALSE(bitmask10);
 }
 
+TEST(PoliciesTests, BitmaskToPolicies) {
+  const auto policies1 = BitmaskToPolicies(PolicyFlags::POLICY_PUBLIC);
+  ASSERT_EQ(1, policies1.size());
+  ASSERT_EQ(policies1[0], "public");
+
+  const auto policies2 = BitmaskToPolicies(PolicyFlags::POLICY_SYSTEM_PARTITION |
+                                           PolicyFlags::POLICY_VENDOR_PARTITION);
+  ASSERT_EQ(2, policies2.size());
+  ASSERT_EQ(policies2[0], "system");
+  ASSERT_EQ(policies2[1], "vendor");
+
+  const auto policies3 = BitmaskToPolicies(
+      PolicyFlags::POLICY_ODM_PARTITION | PolicyFlags::POLICY_OEM_PARTITION |
+      PolicyFlags::POLICY_PUBLIC | PolicyFlags::POLICY_PRODUCT_PARTITION |
+      PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION);
+  ASSERT_EQ(2, policies2.size());
+  ASSERT_EQ(policies3[0], "odm");
+  ASSERT_EQ(policies3[1], "oem");
+  ASSERT_EQ(policies3[2], "public");
+  ASSERT_EQ(policies3[3], "product");
+  ASSERT_EQ(policies3[4], "system");
+  ASSERT_EQ(policies3[5], "vendor");
+}
+
 }  // namespace android::idmap2
diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
index 64518fd..2695176 100644
--- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
@@ -49,7 +49,7 @@
 
   ASSERT_NE(stream.str().find("00000000: 504d4449  magic\n"), std::string::npos);
   ASSERT_NE(stream.str().find("00000004: 00000001  version\n"), std::string::npos);
-  ASSERT_NE(stream.str().find("00000008: d513ca1b  target crc\n"), std::string::npos);
+  ASSERT_NE(stream.str().find("00000008: 76a20829  target crc\n"), std::string::npos);
   ASSERT_NE(stream.str().find("0000000c: 8635c2ed  overlay crc\n"), std::string::npos);
   ASSERT_NE(stream.str().find("0000021c: 00000000  0x7f010000 -> 0x7f010000 integer/int1\n"),
             std::string::npos);
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
index 0270400..9ebfae4 100644
--- a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
@@ -23,6 +23,8 @@
     <!-- Requests to overlay a resource that belongs to a policy the overlay does not fulfill. -->
     <string name="policy_product">policy_product</string>
     <string name="policy_signature">policy_signature</string>
+    <string name="policy_odm">policy_odm</string>
+    <string name="policy_oem">policy_oem</string>
 
     <!-- Requests to overlay a resource that is not declared as overlayable. -->
     <string name="not_overlayable">not_overlayable</string>
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
index 9448939..1456e74 100644
--- a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/res/values/overlayable.xml b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
index 0bf83fa..8389f56 100644
--- a/cmds/idmap2/tests/data/target/res/values/overlayable.xml
+++ b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
@@ -33,6 +33,14 @@
         <item type="string" name="policy_product" />
     </policy>
 
+    <policy type="odm">
+        <item type="string" name="policy_odm" />
+    </policy>
+
+    <policy type="oem">
+        <item type="string" name="policy_oem" />
+    </policy>
+
     <!-- Resources publicly overlayable -->
     <policy type="public">
         <item type="string" name="policy_public" />
diff --git a/cmds/idmap2/tests/data/target/res/values/values.xml b/cmds/idmap2/tests/data/target/res/values/values.xml
index edd53f4..a892c98 100644
--- a/cmds/idmap2/tests/data/target/res/values/values.xml
+++ b/cmds/idmap2/tests/data/target/res/values/values.xml
@@ -29,11 +29,13 @@
     <!-- This resources is not marked as overlayable -->
     <string name="not_overlayable">not_overlayable</string>
 
+    <string name="policy_public">policy_public</string>
+    <string name="policy_odm">policy_odm</string>
+    <string name="policy_oem">policy_oem</string>
+    <string name="policy_product">policy_product</string>
+    <string name="policy_signature">policy_signature</string>
     <string name="policy_system">policy_system</string>
     <string name="policy_system_vendor">policy_system_vendor</string>
-    <string name="policy_product">policy_product</string>
-    <string name="policy_public">policy_public</string>
-    <string name="policy_signature">policy_signature</string>
 
-    <item type="string" name="other" />
+    <string name="other">other</string>
 </resources>
diff --git a/cmds/idmap2/tests/data/target/target-no-overlayable.apk b/cmds/idmap2/tests/data/target/target-no-overlayable.apk
index 908b54a..033305a 100644
--- a/cmds/idmap2/tests/data/target/target-no-overlayable.apk
+++ b/cmds/idmap2/tests/data/target/target-no-overlayable.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/target.apk b/cmds/idmap2/tests/data/target/target.apk
index da3c1ae..9bcd6dc 100644
--- a/cmds/idmap2/tests/data/target/target.apk
+++ b/cmds/idmap2/tests/data/target/target.apk
Binary files differ
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index d28108c..dbf0c3a 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -5467,9 +5467,11 @@
         UNKNOWN = 20;
         ATTENTION_SUCCESS_ABSENT = 0;
         ATTENTION_SUCCESS_PRESENT = 1;
-        ATTENTION_FAILURE_PREEMPTED = 2;
-        ATTENTION_FAILURE_TIMED_OUT = 3;
-        ATTENTION_FAILURE_UNKNOWN = 4;
+        ATTENTION_FAILURE_UNKNOWN = 2;
+        ATTENTION_FAILURE_CANCELLED = 3;
+        ATTENTION_FAILURE_PREEMPTED = 4;
+        ATTENTION_FAILURE_TIMED_OUT = 5;
+        ATTENTION_FAILURE_CAMERA_PERMISSION_ABSENT = 6;
     }
     optional AttentionCheckResult attention_check_result = 1 [default = UNKNOWN];
 }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index cf4ef20..17368b7 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1863,7 +1863,7 @@
             mTopActivityComponent = ComponentName.readFromParcel(source);
             mSnapshot = source.readParcelable(null /* classLoader */);
             int colorSpaceId = source.readInt();
-            mColorSpace = colorSpaceId >= 0
+            mColorSpace = colorSpaceId >= 0 && colorSpaceId < ColorSpace.Named.values().length
                     ? ColorSpace.get(ColorSpace.Named.values()[colorSpaceId])
                     : ColorSpace.get(ColorSpace.Named.SRGB);
             mOrientation = source.readInt();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 5248329..0c6c77f 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -8645,19 +8645,29 @@
          * @return whether this bubble should suppress the initial notification when it is posted.
          *
          * @see BubbleMetadata.Builder#setSuppressInitialNotification(boolean)
-         * @deprecated TO BE REMOVED, use {@link #getSuppressNotification()} instead.
+         * @deprecated TO BE REMOVED, use {@link #isNotificationSuppressed()} instead.
          */
         @Deprecated
         public boolean getSuppressInitialNotification() {
-            return (mFlags & FLAG_SUPPRESS_NOTIFICATION) != 0;
+            return isNotificationSuppressed();
         }
 
         /**
          * @return whether this bubble should suppress the notification when it is posted.
          *
-         * @see BubbleMetadata.Builder#setSuppressInitialNotification(boolean)
+         * @see BubbleMetadata.Builder#setSuppressNotification(boolean)
+         * @deprecated TO BE REMOVED, use {@link #isNotificationSuppressed()} instead.
          */
         public boolean getSuppressNotification() {
+            return isNotificationSuppressed();
+        }
+
+        /**
+         * @return whether this bubble should suppress the notification when it is posted.
+         *
+         * @see BubbleMetadata.Builder#setSuppressNotification(boolean)
+         */
+        public boolean isNotificationSuppressed() {
             return (mFlags & FLAG_SUPPRESS_NOTIFICATION) != 0;
         }
 
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index bff8328..c50d003 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -1150,8 +1150,11 @@
          * {@code IMG1024.BURST001.JPG} and {@code IMG1024.BURST002.JPG}
          * will have the same {@link #GROUP_ID} because the first portion of
          * their filenames is identical.
+         *
+         * @removed
          */
         @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
+        @Deprecated
         public static final String GROUP_ID = "group_id";
 
         /**
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index f21fa5e..646aa13 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -764,12 +764,11 @@
         KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
         mBinder.asBinder().linkToDeath(promise, 0);
         try {
-            KeyCharacteristicsCallbackResult result = null;
             int error = mBinder.importWrappedKey(promise, wrappedKeyAlias, wrappedKey,
                     wrappingKeyAlias, maskingKey, args, rootSid, fingerprintSid);
             if (error != NO_ERROR) return error;
 
-            KeyCharacteristicsCallbackResult esult = promise.getFuture().get();
+            KeyCharacteristicsCallbackResult result = promise.getFuture().get();
 
             error = result.getKeystoreResponse().getErrorCode();
             if (error != NO_ERROR) return error;
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 875b90b..fc635aa 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1651,6 +1651,14 @@
     // The overlay must be signed with the same signature as the actor of the target resource,
     // which can be separate or the same as the target package with the resource.
     POLICY_SIGNATURE = 0x00000010,
+
+    // The overlay must reside of the odm partition or must have existed on the odm
+    // partition before an upgrade to overlay these resources.
+    POLICY_ODM_PARTITION = 0x00000020,
+
+    // The overlay must reside of the oem partition or must have existed on the oem
+    // partition before an upgrade to overlay these resources.
+    POLICY_OEM_PARTITION = 0x00000040,
   };
   uint32_t policy_flags;
 
diff --git a/media/apex/java/android/media/MediaSession2Service.java b/media/apex/java/android/media/MediaSession2Service.java
index 28ead99..3f392d2 100644
--- a/media/apex/java/android/media/MediaSession2Service.java
+++ b/media/apex/java/android/media/MediaSession2Service.java
@@ -370,10 +370,6 @@
                             }
                             return;
                         }
-                        if (DEBUG) {
-                            Log.d(TAG, "Handling incoming connection request from the"
-                                    + " controller, controller=" + caller + ", uid=" + uid);
-                        }
 
                         String callingPkg = connectionRequest.getString(KEY_PACKAGE_NAME);
                         // The Binder.getCallingPid() can be 0 for an oneway call from the
@@ -389,13 +385,18 @@
                                 caller,
                                 connectionRequest.getBundle(KEY_CONNECTION_HINTS));
 
+                        if (DEBUG) {
+                            Log.d(TAG, "Handling incoming connection request from the"
+                                    + " controller=" + controllerInfo);
+                        }
+
                         final MediaSession2 session;
                         session = service.onGetSession(controllerInfo);
 
                         if (session == null) {
                             if (DEBUG) {
                                 Log.d(TAG, "Rejecting incoming connection request from the"
-                                        + " controller, controller=" + caller + ", uid=" + uid);
+                                        + " controller=" + controllerInfo);
                             }
                             // Note: Trusted controllers also can be rejected according to the
                             // service implementation.
diff --git a/packages/Shell/res/values-ca/strings.xml b/packages/Shell/res/values-ca/strings.xml
index 048c94d..7fac740 100644
--- a/packages/Shell/res/values-ca/strings.xml
+++ b/packages/Shell/res/values-ca/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="3701846017049540910">"Protecció"</string>
-    <string name="bugreport_notification_channel" msgid="2574150205913861141">"Informes d\'error"</string>
+    <string name="bugreport_notification_channel" msgid="2574150205913861141">"Informes d\'errors"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"S\'està generant l\'informe d\'errors <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"S\'ha capturat l\'informe d\'errors <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"S\'estan afegint detalls a l\'informe d\'errors"</string>
@@ -30,7 +30,7 @@
     <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Toca per compartir l\'informe d\'errors sense captura de pantalla o espera que es creï la captura"</string>
     <string name="bugreport_confirm" msgid="5917407234515812495">"Els informes d\'errors contenen dades dels diferents fitxers de registre del sistema, inclosa informació que pot ser confidencial (com ara l\'ús d\'aplicacions i les dades d\'ubicació). Comparteix-los només amb aplicacions i persones de confiança."</string>
     <string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"No ho tornis a mostrar"</string>
-    <string name="bugreport_storage_title" msgid="5332488144740527109">"Informes d\'error"</string>
+    <string name="bugreport_storage_title" msgid="5332488144740527109">"Informes d\'errors"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"No s\'ha pogut llegir el fitxer de l\'informe d\'errors"</string>
     <string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"No s\'ha pogut afegir la informació detallada de l\'informe d\'errors al fitxer ZIP"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"sense nom"</string>
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
index 58d50ea..6c6c927 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
@@ -28,7 +28,7 @@
 public interface ClockPlugin extends Plugin {
 
     String ACTION = "com.android.systemui.action.PLUGIN_CLOCK";
-    int VERSION = 4;
+    int VERSION = 5;
 
     /**
      * Get the name of the clock face.
@@ -72,6 +72,14 @@
     }
 
     /**
+     * Returns the preferred Y position of the clock.
+     *
+     * @param totalHeight Height of the parent container.
+     * @return preferred Y position.
+     */
+    int getPreferredY(int totalHeight);
+
+    /**
      * Allows the plugin to clean up resources when no longer needed.
      *
      * Called when the view previously created by {@link ClockPlugin#getView()} has been detached
diff --git a/packages/SystemUI/res-keyguard/layout/analog_clock.xml b/packages/SystemUI/res-keyguard/layout/analog_clock.xml
index cf6d35ee2..ee0df48 100644
--- a/packages/SystemUI/res-keyguard/layout/analog_clock.xml
+++ b/packages/SystemUI/res-keyguard/layout/analog_clock.xml
@@ -19,22 +19,6 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
   >
-  <TextClock
-      android:id="@+id/digital_clock"
-      android:paddingStart="20dp"
-      android:layout_marginTop="72dp"
-      android:layout_width="match_parent"
-      android:layout_height="wrap_content"
-      android:layout_gravity="top|left"
-      android:textSize="44dp"
-      android:letterSpacing="0.05"
-      android:textColor="?attr/wallpaperTextColor"
-      android:singleLine="true"
-      style="@style/widget_big"
-      android:format12Hour="@string/keyguard_widget_12_hours_format"
-      android:format24Hour="@string/keyguard_widget_24_hours_format"
-      android:elegantTextHeight="false"
-  />
   <com.android.keyguard.clock.ImageClock
       android:id="@+id/analog_clock"
       android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res-keyguard/layout/bubble_clock.xml b/packages/SystemUI/res-keyguard/layout/bubble_clock.xml
index f945b10..b44faa9 100644
--- a/packages/SystemUI/res-keyguard/layout/bubble_clock.xml
+++ b/packages/SystemUI/res-keyguard/layout/bubble_clock.xml
@@ -19,22 +19,6 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
   >
-  <TextClock
-      android:id="@+id/digital_clock"
-      android:paddingStart="20dp"
-      android:layout_marginTop="72dp"
-      android:layout_width="match_parent"
-      android:layout_height="wrap_content"
-      android:layout_gravity="top|left"
-      android:textSize="44dp"
-      android:letterSpacing="0.05"
-      android:textColor="?attr/wallpaperTextColor"
-      android:singleLine="true"
-      style="@style/widget_big"
-      android:format12Hour="@string/keyguard_widget_12_hours_format"
-      android:format24Hour="@string/keyguard_widget_24_hours_format"
-      android:elegantTextHeight="false"
-  />
   <com.android.keyguard.clock.ImageClock
       android:id="@+id/analog_clock"
       android:layout_width="wrap_content"
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 70366a8..fbb30d2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -298,6 +298,20 @@
     }
 
     /**
+     * Returns the preferred Y position of the clock.
+     *
+     * @param totalHeight Height of the parent container.
+     * @return preferred Y position.
+     */
+    int getPreferredY(int totalHeight) {
+        if (mClockPlugin != null) {
+            return mClockPlugin.getPreferredY(totalHeight);
+        } else {
+            return totalHeight / 2;
+        }
+    }
+
+    /**
      * Refresh the time of the clock, due to either time tick broadcast or doze time tick alarm.
      */
     public void refresh() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 0369e4c..b02d514 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -241,6 +241,16 @@
         return mClockView.getTextSize();
     }
 
+    /**
+     * Returns the preferred Y position of the clock.
+     *
+     * @param totalHeight The height available to position the clock.
+     * @return Y position of clock.
+     */
+    public int getClockPreferredY(int totalHeight) {
+        return mClockView.getPreferredY(totalHeight);
+    }
+
     private void updateLogoutView() {
         if (mLogoutView == null) {
             return;
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java
index 1652121..7d1587c 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java
@@ -21,6 +21,7 @@
 import android.graphics.BitmapFactory;
 import android.graphics.Color;
 import android.graphics.Paint.Style;
+import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.TextClock;
@@ -61,7 +62,6 @@
      * Custom clock shown on AOD screen and behind stack scroller on lock.
      */
     private ClockLayout mBigClockView;
-    private TextClock mDigitalClock;
     private ImageClock mAnalogClock;
 
     /**
@@ -71,11 +71,6 @@
     private TextClock mLockClock;
 
     /**
-     * Controller for transition to dark state.
-     */
-    private CrossFadeDarkController mDarkController;
-
-    /**
      * Create a BubbleClockController instance.
      *
      * @param res Resources contains title and thumbnail.
@@ -92,24 +87,20 @@
     private void createViews() {
         mBigClockView = (ClockLayout) mLayoutInflater.inflate(R.layout.analog_clock, null);
         mAnalogClock = mBigClockView.findViewById(R.id.analog_clock);
-        mDigitalClock = mBigClockView.findViewById(R.id.digital_clock);
 
         mView = mLayoutInflater.inflate(R.layout.digital_clock, null);
         mLockClock = mView.findViewById(R.id.lock_screen_clock);
-        mLockClock.setVisibility(View.GONE);
-
-        mDarkController = new CrossFadeDarkController(mDigitalClock, mLockClock);
+        final int textSize = mResources.getDimensionPixelSize(R.dimen.widget_title_font_size);
+        mLockClock.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
     }
 
 
     @Override
     public void onDestroyView() {
         mBigClockView = null;
-        mDigitalClock = null;
         mAnalogClock = null;
         mView = null;
         mLockClock = null;
-        mDarkController = null;
     }
 
     @Override
@@ -161,12 +152,15 @@
     }
 
     @Override
+    public int getPreferredY(int totalHeight) {
+        return totalHeight / 4;
+    }
+
+    @Override
     public void setStyle(Style style) {}
 
     @Override
-    public void setTextColor(int color) {
-        mLockClock.setTextColor(color);
-    }
+    public void setTextColor(int color) { }
 
     @Override
     public void setColorPalette(boolean supportsDarkText, int[] colorPalette) {
@@ -174,7 +168,7 @@
             return;
         }
         final int length = colorPalette.length;
-        mDigitalClock.setTextColor(colorPalette[Math.max(0, length - 5)]);
+        mLockClock.setTextColor(colorPalette[Math.max(0, length - 2)]);
         mAnalogClock.setClockColors(colorPalette[Math.max(0, length - 5)],
                 colorPalette[Math.max(0, length - 2)]);
     }
@@ -183,14 +177,11 @@
     public void onTimeTick() {
         mAnalogClock.onTimeChanged();
         mBigClockView.onTimeChanged();
-        mDigitalClock.refresh();
         mLockClock.refresh();
     }
 
     @Override
-    public void setDarkAmount(float darkAmount) {
-        mDarkController.setDarkAmount(darkAmount);
-    }
+    public void setDarkAmount(float darkAmount) { }
 
     @Override
     public void onTimeZoneChanged(TimeZone timeZone) {
@@ -199,6 +190,6 @@
 
     @Override
     public boolean shouldShowStatusArea() {
-        return false;
+        return true;
     }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
index 6069a5e..cadfb79 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
@@ -21,6 +21,7 @@
 import android.graphics.BitmapFactory;
 import android.graphics.Color;
 import android.graphics.Paint.Style;
+import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.TextClock;
@@ -61,7 +62,6 @@
      * Custom clock shown on AOD screen and behind stack scroller on lock.
      */
     private ClockLayout mView;
-    private TextClock mDigitalClock;
     private ImageClock mAnalogClock;
 
     /**
@@ -71,11 +71,6 @@
     private TextClock mLockClock;
 
     /**
-     * Controller for transition to dark state.
-     */
-    private CrossFadeDarkController mDarkController;
-
-    /**
      * Create a BubbleClockController instance.
      *
      * @param res Resources contains title and thumbnail.
@@ -91,24 +86,20 @@
 
     private void createViews() {
         mView = (ClockLayout) mLayoutInflater.inflate(R.layout.bubble_clock, null);
-        mDigitalClock = (TextClock) mView.findViewById(R.id.digital_clock);
         mAnalogClock = (ImageClock) mView.findViewById(R.id.analog_clock);
 
         mLockClockContainer = mLayoutInflater.inflate(R.layout.digital_clock, null);
         mLockClock = (TextClock) mLockClockContainer.findViewById(R.id.lock_screen_clock);
-        mLockClock.setVisibility(View.GONE);
-
-        mDarkController = new CrossFadeDarkController(mDigitalClock, mLockClock);
+        final int textSize = mResources.getDimensionPixelSize(R.dimen.widget_title_font_size);
+        mLockClock.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
     }
 
     @Override
     public void onDestroyView() {
         mView = null;
-        mDigitalClock = null;
         mAnalogClock = null;
         mLockClockContainer = null;
         mLockClock = null;
-        mDarkController = null;
     }
 
     @Override
@@ -160,12 +151,15 @@
     }
 
     @Override
+    public int getPreferredY(int totalHeight) {
+        return totalHeight / 4;
+    }
+
+    @Override
     public void setStyle(Style style) {}
 
     @Override
-    public void setTextColor(int color) {
-        mLockClock.setTextColor(color);
-    }
+    public void setTextColor(int color) { }
 
     @Override
     public void setColorPalette(boolean supportsDarkText, int[] colorPalette) {
@@ -173,21 +167,18 @@
             return;
         }
         final int length = colorPalette.length;
-        mDigitalClock.setTextColor(colorPalette[Math.max(0, length - 6)]);
+        mLockClock.setTextColor(colorPalette[Math.max(0, length - 3)]);
         mAnalogClock.setClockColors(colorPalette[Math.max(0, length - 6)],
                 colorPalette[Math.max(0, length - 3)]);
     }
 
     @Override
-    public void setDarkAmount(float darkAmount) {
-        mDarkController.setDarkAmount(darkAmount);
-    }
+    public void setDarkAmount(float darkAmount) { }
 
     @Override
     public void onTimeTick() {
         mAnalogClock.onTimeChanged();
         mView.onTimeChanged();
-        mDigitalClock.refresh();
         mLockClock.refresh();
     }
 
@@ -198,6 +189,6 @@
 
     @Override
     public boolean shouldShowStatusArea() {
-        return false;
+        return true;
     }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
index 55088a8..962b8f8 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
@@ -22,7 +22,6 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.FrameLayout;
-import android.widget.FrameLayout.LayoutParams;
 
 import com.android.keyguard.R;
 
@@ -36,11 +35,10 @@
     /**
      * Clock face views.
      */
-    private View mDigitalClock;
     private View mAnalogClock;
 
     /**
-     * Pixel shifting amplitidues used to prevent screen burn-in.
+     * Pixel shifting amplitudes used to prevent screen burn-in.
      */
     private int mBurnInPreventionOffsetX;
     private int mBurnInPreventionOffsetY;
@@ -60,7 +58,6 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mDigitalClock = findViewById(R.id.digital_clock);
         mAnalogClock = findViewById(R.id.analog_clock);
 
         // Get pixel shifting X, Y amplitudes from resources.
@@ -87,13 +84,6 @@
         final float offsetY = getBurnInOffset(mBurnInPreventionOffsetY * 2, false)
                 - mBurnInPreventionOffsetY;
 
-        // Put digital clock in two left corner of the screen.
-        if (mDigitalClock != null) {
-            LayoutParams params = (LayoutParams) mDigitalClock.getLayoutParams();
-            mDigitalClock.setX(offsetX + params.leftMargin);
-            mDigitalClock.setY(offsetY + params.topMargin);
-        }
-
         // Put the analog clock in the middle of the screen.
         if (mAnalogClock != null) {
             mAnalogClock.setX(Math.max(0f, 0.5f * (getWidth() - mAnalogClock.getWidth()))
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/DefaultClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/DefaultClockController.java
index 488cb27..ce1f09c 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/DefaultClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/DefaultClockController.java
@@ -145,6 +145,11 @@
     }
 
     @Override
+    public int getPreferredY(int totalHeight) {
+        return totalHeight / 2;
+    }
+
+    @Override
     public void setStyle(Style style) {}
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 6d0141b..d53c6e9 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -595,7 +595,7 @@
 
     private void updateShowInShadeForSuppressNotification(NotificationEntry entry) {
         boolean suppressNotification = entry.getBubbleMetadata() != null
-                && entry.getBubbleMetadata().getSuppressNotification()
+                && entry.getBubbleMetadata().isNotificationSuppressed()
                 && isForegroundApp(mContext, entry.notification.getPackageName());
         entry.setShowInShadeWhenBubble(!suppressNotification);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index 1cc6dc3..0fe5f8a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -33,6 +33,14 @@
      */
     boolean isLockscreenPublicMode(int userId);
 
+    /**
+     * Does a user require a separate work challenge? If so, the unlock mechanism is decoupled from
+     * the current user and has to be solved separately.
+     */
+    default boolean needsSeparateWorkChallenge(int userId) {
+        return false;
+    }
+
     void setUpWithPresenter(NotificationPresenter presenter);
 
     int getCurrentUserId();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 9cb6f11..ed59f79 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -77,6 +77,7 @@
 
     private final DevicePolicyManager mDevicePolicyManager;
     private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray();
+    private final SparseBooleanArray mUsersWithSeperateWorkChallenge = new SparseBooleanArray();
     private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
     private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
     private final UserManager mUserManager;
@@ -394,6 +395,11 @@
         return mLockscreenPublicMode.get(userId, false);
     }
 
+    @Override
+    public boolean needsSeparateWorkChallenge(int userId) {
+        return mUsersWithSeperateWorkChallenge.get(userId, false);
+    }
+
     /**
      * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
      * "public" (secure & locked) mode?
@@ -493,20 +499,23 @@
         //   - device keyguard is shown in secure mode;
         //   - profile is locked with a work challenge.
         SparseArray<UserInfo> currentProfiles = getCurrentProfiles();
+        mUsersWithSeperateWorkChallenge.clear();
         for (int i = currentProfiles.size() - 1; i >= 0; i--) {
             final int userId = currentProfiles.valueAt(i).id;
             boolean isProfilePublic = devicePublic;
+            boolean needsSeparateChallenge = mLockPatternUtils.isSeparateProfileChallengeEnabled(
+                    userId);
             if (!devicePublic && userId != getCurrentUserId()) {
                 // We can't rely on KeyguardManager#isDeviceLocked() for unified profile challenge
                 // due to a race condition where this code could be called before
                 // TrustManagerService updates its internal records, resulting in an incorrect
                 // state being cached in mLockscreenPublicMode. (b/35951989)
-                if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
-                        && isSecure(userId)) {
+                if (needsSeparateChallenge && isSecure(userId)) {
                     isProfilePublic = mKeyguardManager.isDeviceLocked(userId);
                 }
             }
             setLockscreenPublicMode(isProfilePublic, userId);
+            mUsersWithSeperateWorkChallenge.put(userId, needsSeparateChallenge);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 97f2dd0..b3da62e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.os.Trace;
+import android.os.UserHandle;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
@@ -26,6 +27,7 @@
 import com.android.systemui.R;
 import com.android.systemui.bubbles.BubbleData;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -33,6 +35,7 @@
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.UnlockMethodCache;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -52,7 +55,7 @@
  * notifications that might affect their display.
  */
 @Singleton
-public class NotificationViewHierarchyManager {
+public class NotificationViewHierarchyManager implements DynamicPrivacyController.Listener {
     private static final String TAG = "NotificationViewHierarchyManager";
 
     //TODO: change this top <Entry, List<Entry>>?
@@ -76,6 +79,7 @@
      */
     private final boolean mAlwaysExpandNonGroupedNotification;
     private final BubbleData mBubbleData;
+    private final DynamicPrivacyController mDynamicPrivacyController;
 
     private NotificationPresenter mPresenter;
     private NotificationListContainer mListContainer;
@@ -88,7 +92,8 @@
             StatusBarStateController statusBarStateController,
             NotificationEntryManager notificationEntryManager,
             Lazy<ShadeController> shadeController,
-            BubbleData bubbleData) {
+            BubbleData bubbleData,
+            DynamicPrivacyController privacyController) {
         mLockscreenUserManager = notificationLockscreenUserManager;
         mGroupManager = groupManager;
         mVisualStabilityManager = visualStabilityManager;
@@ -99,6 +104,8 @@
         mAlwaysExpandNonGroupedNotification =
                 res.getBoolean(R.bool.config_alwaysExpandNonGroupedNotifications);
         mBubbleData = bubbleData;
+        mDynamicPrivacyController = privacyController;
+        privacyController.addListener(this);
     }
 
     public void setUpWithPresenter(NotificationPresenter presenter,
@@ -130,15 +137,20 @@
             // Display public version of the notification if we need to redact.
             // TODO: This area uses a lot of calls into NotificationLockscreenUserManager.
             // We can probably move some of this code there.
-            boolean devicePublic = mLockscreenUserManager.isLockscreenPublicMode(
-                    mLockscreenUserManager.getCurrentUserId());
+            int currentUserId = mLockscreenUserManager.getCurrentUserId();
+            boolean devicePublic = mLockscreenUserManager.isLockscreenPublicMode(currentUserId);
             boolean userPublic = devicePublic
                     || mLockscreenUserManager.isLockscreenPublicMode(userId);
+            if (userPublic && mDynamicPrivacyController.isDynamicallyUnlocked()
+                    && (userId == currentUserId || userId == UserHandle.USER_ALL
+                    || !mLockscreenUserManager.needsSeparateWorkChallenge(userId))) {
+                userPublic = false;
+            }
             boolean needsRedaction = mLockscreenUserManager.needsRedaction(ent);
             boolean sensitive = userPublic && needsRedaction;
             boolean deviceSensitive = devicePublic
                     && !mLockscreenUserManager.userAllowsPrivateNotificationsInPublic(
-                    mLockscreenUserManager.getCurrentUserId());
+                    currentUserId);
             ent.getRow().setSensitive(sensitive, deviceSensitive);
             ent.getRow().setNeedsRedaction(needsRedaction);
             if (mGroupManager.isChildInGroupWithSummary(ent.notification)) {
@@ -153,7 +165,6 @@
             } else {
                 toShow.add(ent.getRow());
             }
-
         }
 
         ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>();
@@ -406,4 +417,9 @@
         Trace.endSection();
         Trace.endSection();
     }
+
+    @Override
+    public void onDynamicPrivacyChanged() {
+        updateNotificationViews();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java
new file mode 100644
index 0000000..16bd884
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import android.content.Context;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.phone.UnlockMethodCache;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * A controller which dynamically controls the visibility of Notification content
+ */
+@Singleton
+public class DynamicPrivacyController implements UnlockMethodCache.OnUnlockMethodChangedListener {
+
+    private final UnlockMethodCache mUnlockMethodCache;
+    private final NotificationLockscreenUserManager mLockscreenUserManager;
+    private ArraySet<Listener> mListeners = new ArraySet<>();
+
+    private boolean mLastDynamicUnlocked;
+    private boolean mCacheInvalid;
+
+    @Inject
+    DynamicPrivacyController(Context context,
+            NotificationLockscreenUserManager notificationLockscreenUserManager) {
+        this(notificationLockscreenUserManager, UnlockMethodCache.getInstance(context));
+    }
+
+    @VisibleForTesting
+    DynamicPrivacyController(NotificationLockscreenUserManager notificationLockscreenUserManager,
+            UnlockMethodCache unlockMethodCache) {
+        mLockscreenUserManager = notificationLockscreenUserManager;
+        mUnlockMethodCache = unlockMethodCache;
+        mUnlockMethodCache.addListener(this);
+        mLastDynamicUnlocked = isDynamicallyUnlocked();
+    }
+
+    @Override
+    public void onUnlockMethodStateChanged() {
+        if (isDynamicPrivacyEnabled()) {
+            // We only want to notify our listeners if dynamic privacy is actually active
+            boolean dynamicallyUnlocked = isDynamicallyUnlocked();
+            if (dynamicallyUnlocked != mLastDynamicUnlocked || mCacheInvalid) {
+                mLastDynamicUnlocked = dynamicallyUnlocked;
+                for (Listener listener : mListeners) {
+                    listener.onDynamicPrivacyChanged();
+                }
+            }
+            mCacheInvalid = false;
+        } else {
+            mCacheInvalid = true;
+        }
+    }
+
+    private boolean isDynamicPrivacyEnabled() {
+        return !mLockscreenUserManager.shouldHideNotifications(
+                mLockscreenUserManager.getCurrentUserId());
+    }
+
+    public boolean isDynamicallyUnlocked() {
+        return mUnlockMethodCache.canSkipBouncer() && isDynamicPrivacyEnabled();
+    }
+
+    public void addListener(Listener listener) {
+        mListeners.add(listener);
+    }
+
+    public interface Listener {
+        void onDynamicPrivacyChanged();
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 09f513d..18dcf4c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -120,8 +120,6 @@
     @InflationFlag
     private int mInflationFlags = REQUIRED_INFLATION_FLAGS;
 
-    static final InflationExecutor EXECUTOR = new InflationExecutor();
-
     private final ExpandableNotificationRow mRow;
     private boolean mIsLowPriority;
     private boolean mUsesIncreasedHeight;
@@ -638,14 +636,14 @@
             cancellationSignal = newContentView.applyAsync(
                     result.packageContext,
                     parentLayout,
-                    EXECUTOR,
+                    null,
                     listener,
                     remoteViewClickHandler);
         } else {
             cancellationSignal = newContentView.reapplyAsync(
                     result.packageContext,
                     existingView,
-                    EXECUTOR,
+                    null,
                     listener,
                     remoteViewClickHandler);
         }
@@ -996,40 +994,4 @@
         public abstract void setResultView(View v);
         public abstract RemoteViews getRemoteView();
     }
-
-    /**
-     * A custom executor that allows more tasks to be queued. Default values are copied from
-     * AsyncTask
-      */
-    private static class InflationExecutor implements Executor {
-        private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
-        // We want at least 2 threads and at most 4 threads in the core pool,
-        // preferring to have 1 less than the CPU count to avoid saturating
-        // the CPU with background work
-        private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
-        private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
-        private static final int KEEP_ALIVE_SECONDS = 30;
-
-        private static final ThreadFactory sThreadFactory = new ThreadFactory() {
-            private final AtomicInteger mCount = new AtomicInteger(1);
-
-            public Thread newThread(Runnable r) {
-                return new Thread(r, "InflaterThread #" + mCount.getAndIncrement());
-            }
-        };
-
-        private final ThreadPoolExecutor mExecutor;
-
-        private InflationExecutor() {
-            mExecutor = new ThreadPoolExecutor(
-                    CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
-                    new LinkedBlockingQueue<>(), sThreadFactory);
-            mExecutor.allowCoreThreadTimeOut(true);
-        }
-
-        @Override
-        public void execute(Runnable runnable) {
-            mExecutor.execute(runnable);
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
index 6eb376b..4b0e2ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
@@ -52,7 +52,7 @@
     @Override
     public void preload(Uri uri) {
         PreloadImageTask newTask = new PreloadImageTask(mResolver);
-        newTask.executeOnExecutor(NotificationContentInflater.EXECUTOR, uri);
+        newTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, uri);
         mCache.put(uri, newTask);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 562e535..058cb2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -101,6 +101,7 @@
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.FakeShadowView;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -153,7 +154,8 @@
  * A layout which handles a dynamic amount of notifications and presents them in a scrollable stack.
  */
 public class NotificationStackScrollLayout extends ViewGroup implements ScrollAdapter,
-        NotificationListContainer, ConfigurationListener, Dumpable {
+        NotificationListContainer, ConfigurationListener, Dumpable,
+        DynamicPrivacyController.Listener {
 
     public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
     private static final String TAG = "StackScroller";
@@ -498,6 +500,7 @@
      * If the {@link NotificationShelf} should be visible when dark.
      */
     private boolean mShowDarkShelf;
+    private boolean mAnimateBottomOnLayout;
 
     @Inject
     public NotificationStackScrollLayout(
@@ -505,7 +508,8 @@
             AttributeSet attrs,
             @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
             NotificationRoundnessManager notificationRoundnessManager,
-            AmbientPulseManager ambientPulseManager) {
+            AmbientPulseManager ambientPulseManager,
+            DynamicPrivacyController dynamicPrivacyController) {
         super(context, attrs, 0, 0);
         Resources res = getResources();
 
@@ -576,6 +580,7 @@
                 }
             }
         });
+        dynamicPrivacyController.addListener(this);
     }
 
     private void updateDismissRtlSetting(boolean dismissRtl) {
@@ -2479,9 +2484,8 @@
      */
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     private void updateBackgroundBounds() {
-        getLocationInWindow(mTempInt2);
-        int left = mTempInt2[0] + mSidePaddings;
-        int right = mTempInt2[0] + getWidth() - mSidePaddings;
+        int left = mSidePaddings;
+        int right = getWidth() - mSidePaddings;
         for (NotificationSection section : mSections) {
             section.getBounds().left = left;
             section.getBounds().right = right;
@@ -3165,7 +3169,7 @@
 
         if (mAnimationsEnabled && mIsExpanded) {
             mAnimateNextBackgroundTop = firstChild != previousFirstChild;
-            mAnimateNextBackgroundBottom = lastChild != previousLastChild;
+            mAnimateNextBackgroundBottom = lastChild != previousLastChild || mAnimateBottomOnLayout;
             mAnimateNextSectionBoundsChange = sectionViewsChanged;
         } else {
             mAnimateNextBackgroundTop = false;
@@ -3174,6 +3178,7 @@
         }
         mAmbientState.setLastVisibleBackgroundChild(lastChild);
         mRoundnessManager.updateRoundedChildren(mSections);
+        mAnimateBottomOnLayout = false;
         invalidate();
     }
 
@@ -4842,8 +4847,8 @@
      * If the shelf should be visible when the device is in ambient mode (dozing.)
      */
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    public void setShowDarkShelf(boolean showDarkShelf) {
-        mShowDarkShelf = showDarkShelf;
+    public void showDarkShelf() {
+        mShowDarkShelf = true;
     }
 
     private void updateDarkShelfVisibility() {
@@ -5714,6 +5719,14 @@
         }
     }
 
+    @Override
+    public void onDynamicPrivacyChanged() {
+        if (mIsExpanded) {
+            // The bottom might change because we're using the final actual height of the view
+            mAnimateBottomOnLayout = true;
+        }
+    }
+
     /**
      * A listener that is notified when the empty space below the notifications is clicked on
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index 195d02d..5d144a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -220,7 +220,6 @@
         if (mStatusBarStateController.isDozing()
                 && mStatusBarComponent.getPanel().hasCustomClock()) {
             state |= DISABLE_CLOCK | DISABLE_SYSTEM_INFO;
-            state &= ~DISABLE_NOTIFICATION_ICONS;
         }
 
         return state;
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 c68fdd4..d59f248 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -22,7 +22,6 @@
 import android.content.res.Resources;
 import android.util.MathUtils;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.keyguard.KeyguardStatusView;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
@@ -55,6 +54,11 @@
     private int mKeyguardStatusHeight;
 
     /**
+     * Preferred Y position of clock.
+     */
+    private int mClockPreferredY;
+
+    /**
      * Height of notification stack: Sum of height of each notification.
      */
     private int mNotificationStackHeight;
@@ -117,14 +121,15 @@
     }
 
     public void setup(int minTopMargin, int maxShadeBottom, int notificationStackHeight,
-            float panelExpansion, int parentHeight, int keyguardStatusHeight, float dark,
-            boolean secure, float emptyDragAmount) {
+            float panelExpansion, int parentHeight, int keyguardStatusHeight, int clockPreferredY,
+            float dark, boolean secure, float emptyDragAmount) {
         mMinTopMargin = minTopMargin + mContainerTopPadding;
         mMaxShadeBottom = maxShadeBottom;
         mNotificationStackHeight = notificationStackHeight;
         mPanelExpansion = panelExpansion;
         mHeight = parentHeight;
         mKeyguardStatusHeight = keyguardStatusHeight;
+        mClockPreferredY = clockPreferredY;
         mDarkAmount = dark;
         mCurrentlySecure = secure;
         mEmptyDragAmount = emptyDragAmount;
@@ -146,6 +151,10 @@
         return mHeight / 2 - mKeyguardStatusHeight - mClockNotificationsMargin;
     }
 
+    private int getPreferredClockY() {
+        return mClockPreferredY - mKeyguardStatusHeight - mClockNotificationsMargin;
+    }
+
     /**
      * Vertically align the clock and the shade in the available space considering only
      * a percentage of the clock height defined by {@code CLOCK_HEIGHT_WEIGHT}.
@@ -172,7 +181,7 @@
 
     private int getClockY() {
         // Dark: Align the bottom edge of the clock at about half of the screen:
-        float clockYDark = getMaxClockY() + burnInPreventionOffsetY();
+        float clockYDark = getPreferredClockY() + burnInPreventionOffsetY();
         clockYDark = MathUtils.max(0, clockYDark);
 
         float clockYRegular = getExpandedClockPosition();
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 dd957b4..ab13149 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -78,6 +78,7 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.AnimatableProperty;
+import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.PropertyAnimator;
@@ -109,7 +110,7 @@
         KeyguardAffordanceHelper.Callback, NotificationStackScrollLayout.OnEmptySpaceClickListener,
         OnHeadsUpChangedListener, QS.HeightListener, ZenModeController.Callback,
         ConfigurationController.ConfigurationListener, StateListener,
-        PulseExpansionHandler.ExpansionCallback {
+        PulseExpansionHandler.ExpansionCallback, DynamicPrivacyController.Listener {
 
     private static final boolean DEBUG = false;
 
@@ -208,9 +209,9 @@
     private int mUnlockMoveDistance;
     private float mEmptyDragAmount;
 
-    private KeyguardClockPositionAlgorithm mClockPositionAlgorithm =
+    private final KeyguardClockPositionAlgorithm mClockPositionAlgorithm =
             new KeyguardClockPositionAlgorithm();
-    private KeyguardClockPositionAlgorithm.Result mClockPositionResult =
+    private final KeyguardClockPositionAlgorithm.Result mClockPositionResult =
             new KeyguardClockPositionAlgorithm.Result();
     private boolean mIsExpanding;
 
@@ -343,7 +344,8 @@
     public NotificationPanelView(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
             InjectionInflationController injectionInflationController,
             NotificationWakeUpCoordinator coordinator,
-            PulseExpansionHandler pulseExpansionHandler) {
+            PulseExpansionHandler pulseExpansionHandler,
+            DynamicPrivacyController dynamicPrivacyController) {
         super(context, attrs);
         setWillNotDraw(!DEBUG);
         mInjectionInflationController = injectionInflationController;
@@ -358,6 +360,7 @@
         mDisplayId = context.getDisplayId();
         mPulseExpansionHandler = pulseExpansionHandler;
         mThemeResId = context.getThemeResId();
+        dynamicPrivacyController.addListener(this);
     }
 
     /**
@@ -627,6 +630,7 @@
         } else {
             int totalHeight = getHeight();
             int bottomPadding = Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding);
+            int clockPreferredY = mKeyguardStatusView.getClockPreferredY(totalHeight);
             mClockPositionAlgorithm.setup(
                     mStatusBarMinHeight,
                     totalHeight - bottomPadding,
@@ -634,6 +638,7 @@
                     getExpandedFraction(),
                     totalHeight,
                     mKeyguardStatusView.getHeight(),
+                    clockPreferredY,
                     mInterpolatedDarkAmount,
                     mStatusBar.isKeyguardCurrentlySecure(),
                     mEmptyDragAmount);
@@ -2830,7 +2835,7 @@
         mDozing = dozing;
         mNotificationStackScroller.setDark(mDozing, animate, wakeUpTouchLocation);
         if (mDozing) {
-            mNotificationStackScroller.setShowDarkShelf(!hasCustomClock());
+            mNotificationStackScroller.showDarkShelf();
         }
         mKeyguardBottomArea.setDozing(mDozing, animate);
 
@@ -3113,4 +3118,9 @@
         }
         return y;
     }
+
+    @Override
+    public void onDynamicPrivacyChanged() {
+        mAnimateNextPositionUpdate = true;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
index 44c82c8..39bf728 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
@@ -16,10 +16,18 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.hardware.biometrics.BiometricSourceType;
+import android.media.AudioManager;
+import android.os.Build;
 import android.os.Trace;
+import android.telephony.TelephonyManager;
 
+import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -34,6 +42,8 @@
 public class UnlockMethodCache {
 
     private static UnlockMethodCache sInstance;
+    private static final boolean DEBUG_AUTH_WITH_ADB = false;
+    private static final String AUTH_BROADCAST_KEY = "debug_trigger_auth";
 
     private final LockPatternUtils mLockPatternUtils;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -44,12 +54,27 @@
     private boolean mCanSkipBouncer;
     private boolean mTrustManaged;
     private boolean mTrusted;
+    private boolean mDebugUnlocked = false;
 
     private UnlockMethodCache(Context ctx) {
         mLockPatternUtils = new LockPatternUtils(ctx);
         mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(ctx);
         KeyguardUpdateMonitor.getInstance(ctx).registerCallback(mCallback);
         update(true /* updateAlways */);
+        if (Build.IS_DEBUGGABLE && DEBUG_AUTH_WITH_ADB) {
+            // Watch for interesting updates
+            final IntentFilter filter = new IntentFilter();
+            filter.addAction(AUTH_BROADCAST_KEY);
+            ctx.registerReceiver(new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    if (DEBUG_AUTH_WITH_ADB && AUTH_BROADCAST_KEY.equals(intent.getAction())) {
+                        mDebugUnlocked = !mDebugUnlocked;
+                        update(true /* updateAlways */);
+                    }
+                }
+            }, filter, null, null);
+        }
     }
 
     public static UnlockMethodCache getInstance(Context context) {
@@ -89,7 +114,8 @@
         Trace.beginSection("UnlockMethodCache#update");
         int user = KeyguardUpdateMonitor.getCurrentUser();
         boolean secure = mLockPatternUtils.isSecure(user);
-        boolean canSkipBouncer = !secure ||  mKeyguardUpdateMonitor.getUserCanSkipBouncer(user);
+        boolean canSkipBouncer = !secure || mKeyguardUpdateMonitor.getUserCanSkipBouncer(user)
+                || (Build.IS_DEBUGGABLE && DEBUG_AUTH_WITH_ADB && mDebugUnlocked);
         boolean trustManaged = mKeyguardUpdateMonitor.getUserTrustIsManaged(user);
         boolean trusted = mKeyguardUpdateMonitor.getUserHasTrust(user);
         boolean changed = secure != mSecure || canSkipBouncer != mCanSkipBouncer ||
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/AnalogClockControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/AnalogClockControllerTest.java
index 4bb2395..3f48ea7 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/AnalogClockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/AnalogClockControllerTest.java
@@ -54,20 +54,20 @@
     }
 
     @Test
-    public void setDarkAmount_fadeIn() {
+    public void setDarkAmount_AOD() {
         ViewGroup smallClockFrame = (ViewGroup) mClockController.getView();
         View smallClock = smallClockFrame.getChildAt(0);
         // WHEN dark amount is set to AOD
         mClockController.setDarkAmount(1f);
-        // THEN small clock should not be shown.
-        assertThat(smallClock.getVisibility()).isEqualTo(View.GONE);
+        // THEN small clock should be shown.
+        assertThat(smallClock.getVisibility()).isEqualTo(View.VISIBLE);
     }
 
     @Test
-    public void setTextColor_setDigitalClock() {
+    public void setColorPalette_setDigitalClock() {
         ViewGroup smallClock = (ViewGroup) mClockController.getView();
-        // WHEN text color is set
-        mClockController.setTextColor(42);
+        // WHEN color palette is set
+        mClockController.setColorPalette(true, new int[]{42});
         // THEN child of small clock should have text color set.
         TextView digitalClock = (TextView) smallClock.getChildAt(0);
         assertThat(digitalClock.getCurrentTextColor()).isEqualTo(42);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java
index f03c234..90083b4 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java
@@ -53,20 +53,20 @@
     }
 
     @Test
-    public void setDarkAmount_fadeIn() {
+    public void setDarkAmount_AOD() {
         ViewGroup smallClockFrame = (ViewGroup) mClockController.getView();
         View smallClock = smallClockFrame.getChildAt(0);
         // WHEN dark amount is set to AOD
         mClockController.setDarkAmount(1f);
         // THEN small clock should not be shown.
-        assertThat(smallClock.getVisibility()).isEqualTo(View.GONE);
+        assertThat(smallClock.getVisibility()).isEqualTo(View.VISIBLE);
     }
 
     @Test
-    public void setTextColor_setDigitalClock() {
+    public void setColorPalette_setDigitalClock() {
         ViewGroup smallClock = (ViewGroup) mClockController.getView();
         // WHEN text color is set
-        mClockController.setTextColor(42);
+        mClockController.setColorPalette(true, new int[]{42});
         // THEN child of small clock should have text color set.
         TextView digitalClock = (TextView) smallClock.getChildAt(0);
         assertThat(digitalClock.getCurrentTextColor()).isEqualTo(42);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 3662c38..c476d80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -39,6 +39,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.bubbles.BubbleData;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
+import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationData;
@@ -98,7 +99,7 @@
         mViewHierarchyManager = new NotificationViewHierarchyManager(mContext,
                 mLockscreenUserManager, mGroupManager, mVisualStabilityManager,
                 mock(StatusBarStateControllerImpl.class), mEntryManager,
-                () -> mShadeController, new BubbleData(mContext));
+                () -> mShadeController, new BubbleData(mContext), mock(DynamicPrivacyController.class));
         Dependency.get(InitController.class).executePostInitTasks();
         mViewHierarchyManager.setUpWithPresenter(mPresenter, mListContainer);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
new file mode 100644
index 0000000..6ca5d2c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationViewHierarchyManager;
+import com.android.systemui.statusbar.phone.UnlockMethodCache;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import dagger.Lazy;
+
+
+@SmallTest
+@org.junit.runner.RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class DynamicPrivacyControllerTest extends SysuiTestCase {
+
+    private DynamicPrivacyController mDynamicPrivacyController;
+    private UnlockMethodCache mCache = mock(UnlockMethodCache.class);
+    private NotificationLockscreenUserManager mLockScreenUserManager
+            = mock(NotificationLockscreenUserManager.class);
+    private DynamicPrivacyController.Listener mListener
+            = mock(DynamicPrivacyController.Listener.class);
+
+    @Before
+    public void setUp() throws Exception {
+        when(mCache.canSkipBouncer()).thenReturn(false);
+        mDynamicPrivacyController = new DynamicPrivacyController(
+                mLockScreenUserManager, mCache);
+        mDynamicPrivacyController.addListener(mListener);
+    }
+
+    @Test
+    public void testDynamicFalseWhenCannotSkipBouncer() {
+        enableDynamicPrivacy();
+        when(mCache.canSkipBouncer()).thenReturn(false);
+        Assert.assertFalse("can't skip bouncer but is dynamically unlocked",
+                mDynamicPrivacyController.isDynamicallyUnlocked());
+    }
+
+    @Test
+    public void testDynamicTrueWhenCanSkipBouncer() {
+        enableDynamicPrivacy();
+        when(mCache.canSkipBouncer()).thenReturn(true);
+        Assert.assertTrue("Isn't dynamically unlocked even though we can skip bouncer",
+                mDynamicPrivacyController.isDynamicallyUnlocked());
+    }
+
+    @Test
+    public void testNotifiedWhenEnabled() {
+        when(mCache.canSkipBouncer()).thenReturn(true);
+        enableDynamicPrivacy();
+        mDynamicPrivacyController.onUnlockMethodStateChanged();
+        verify(mListener).onDynamicPrivacyChanged();
+    }
+
+    private void enableDynamicPrivacy() {
+        when(mLockScreenUserManager.shouldHideNotifications(any())).thenReturn(
+                false);
+    }
+
+    @Test
+    public void testNotNotifiedWithoutNotifications() {
+        when(mCache.canSkipBouncer()).thenReturn(true);
+        when(mLockScreenUserManager.shouldHideNotifications(anyInt())).thenReturn(
+                true);
+        mDynamicPrivacyController.onUnlockMethodStateChanged();
+        verifyNoMoreInteractions(mListener);
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 1f57593..04f911a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -60,6 +60,7 @@
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -144,7 +145,8 @@
         // member variables, not the spy's member variables.
         mStackScrollerInternal = new NotificationStackScrollLayout(getContext(), null,
                 true /* allowLongPress */, mNotificationRoundnessManager,
-                new AmbientPulseManager(mContext));
+                new AmbientPulseManager(mContext),
+                mock(DynamicPrivacyController.class));
         mStackScroller = spy(mStackScrollerInternal);
         mStackScroller.setShelf(notificationShelf);
         mStackScroller.setStatusBar(mBar);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
index fcf4c71..3f4d96c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
@@ -35,6 +35,7 @@
 public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
 
     private static final int SCREEN_HEIGHT = 2000;
+    private static final int PREFERRED_CLOCK_Y = SCREEN_HEIGHT / 2;
     private static final int EMPTY_MARGIN = 0;
     private static final int EMPTY_HEIGHT = 0;
     private static final boolean SECURE_LOCKED = false;
@@ -305,8 +306,8 @@
 
     private void positionClock() {
         mClockPositionAlgorithm.setup(EMPTY_MARGIN, SCREEN_HEIGHT, mNotificationStackHeight,
-                mPanelExpansion, SCREEN_HEIGHT, mKeyguardStatusHeight, mDark, SECURE_LOCKED,
-                ZERO_DRAG);
+                mPanelExpansion, SCREEN_HEIGHT, mKeyguardStatusHeight, PREFERRED_CLOCK_Y, mDark,
+                SECURE_LOCKED, ZERO_DRAG);
         mClockPositionAlgorithm.run(mClockPosition);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 6d6af47..08471d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -20,6 +20,7 @@
 
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -40,6 +41,7 @@
 import com.android.systemui.statusbar.PulseExpansionHandler;
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -117,7 +119,7 @@
         mNotificationPanelView.setDozing(true /* dozing */, true /* animate */, null /* touch */);
         InOrder inOrder = inOrder(mNotificationStackScrollLayout, mStatusBarStateController);
         inOrder.verify(mNotificationStackScrollLayout).setDark(eq(true), eq(true), eq(null));
-        inOrder.verify(mNotificationStackScrollLayout).setShowDarkShelf(eq(true));
+        inOrder.verify(mNotificationStackScrollLayout).showDarkShelf();
         inOrder.verify(mStatusBarStateController).setDozeAmount(eq(1f), eq(true));
     }
 
@@ -125,14 +127,14 @@
     public void testSetDozing_showsDarkShelfWithDefaultClock() {
         when(mKeyguardStatusView.hasCustomClock()).thenReturn(false);
         mNotificationPanelView.setDozing(true /* dozing */, true /* animate */, null /* touch */);
-        verify(mNotificationStackScrollLayout).setShowDarkShelf(eq(true));
+        verify(mNotificationStackScrollLayout).showDarkShelf();
     }
 
     @Test
-    public void testSetDozing_hidesDarkShelfWhenCustomClock() {
+    public void testSetDozing_showsDarkShelfWhenCustomClock() {
         when(mKeyguardStatusView.hasCustomClock()).thenReturn(true);
         mNotificationPanelView.setDozing(true /* dozing */, true /* animate */, null /* touch */);
-        verify(mNotificationStackScrollLayout).setShowDarkShelf(eq(false));
+        verify(mNotificationStackScrollLayout).showDarkShelf();
     }
 
     @Test
@@ -172,7 +174,7 @@
             super(NotificationPanelViewTest.this.mContext, null,
                     new InjectionInflationController(
                             SystemUIFactory.getInstance().getRootComponent()),
-                    coordinator, expansionHandler);
+                    coordinator, expansionHandler, mock(DynamicPrivacyController.class));
             mNotificationStackScroller = mNotificationStackScrollLayout;
             mKeyguardStatusView = NotificationPanelViewTest.this.mKeyguardStatusView;
             mKeyguardStatusBar = NotificationPanelViewTest.this.mKeyguardStatusBar;
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index fd68a8b..4b435de 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -220,9 +220,19 @@
             return fulfilledPolicies | IIdmap2.POLICY_PRODUCT_PARTITION;
         }
 
+        // Odm partition (/odm)
+        if (ai.isOdm()) {
+            return fulfilledPolicies | IIdmap2.POLICY_ODM_PARTITION;
+        }
+
+        // Oem partition (/oem)
+        if (ai.isOem()) {
+            return fulfilledPolicies | IIdmap2.POLICY_OEM_PARTITION;
+        }
+
         // Check partitions for which there exists no policy so overlays on these partitions will
         // not fulfill the system policy.
-        if (ai.isOem() || ai.isProductServices()) {
+        if (ai.isProductServices()) {
             return fulfilledPolicies;
         }
 
diff --git a/services/core/java/com/android/server/os/SchedulingPolicyService.java b/services/core/java/com/android/server/os/SchedulingPolicyService.java
index 5cbe1a1..2371b04 100644
--- a/services/core/java/com/android/server/os/SchedulingPolicyService.java
+++ b/services/core/java/com/android/server/os/SchedulingPolicyService.java
@@ -40,7 +40,7 @@
     private static final int PRIORITY_MAX = 3;
 
     private static final String[] MEDIA_PROCESS_NAMES = new String[] {
-            "media.codec", // vendor/bin/hw/android.hardware.media.omx@1.0-service
+            "media.swcodec", // /apex/com.android.media.swcodec/bin/mediaswcodec
     };
     private final IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
         @Override
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 5e8d870..fe401e2 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -1143,34 +1143,38 @@
       } else if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
         // Parse the polices separated by vertical bar characters to allow for specifying multiple
         // policies. Items within the policy tag will have the specified policy.
-        for (StringPiece part : util::Tokenize(maybe_type.value(), '|')) {
+        static const auto kPolicyMap =
+            ImmutableMap<StringPiece, OverlayableItem::Policy>::CreatePreSorted({
+                {"odm", OverlayableItem::Policy::kOdm},
+                {"oem", OverlayableItem::Policy::kOem},
+                {"product", OverlayableItem::Policy::kProduct},
+                {"public", OverlayableItem::Policy::kPublic},
+                {"signature", OverlayableItem::Policy::kSignature},
+                {"system", OverlayableItem::Policy::kSystem},
+                {"vendor", OverlayableItem::Policy::kVendor},
+            });
+
+        for (const StringPiece& part : util::Tokenize(maybe_type.value(), '|')) {
           StringPiece trimmed_part = util::TrimWhitespace(part);
-          if (trimmed_part == "public") {
-            current_policies |= OverlayableItem::Policy::kPublic;
-          } else if (trimmed_part == "product") {
-            current_policies |= OverlayableItem::Policy::kProduct;
-          } else if (trimmed_part == "system") {
-            current_policies |= OverlayableItem::Policy::kSystem;
-          } else if (trimmed_part == "vendor") {
-            current_policies |= OverlayableItem::Policy::kVendor;
-          } else if (trimmed_part == "signature") {
-            current_policies |= OverlayableItem::Policy::kSignature;
-          } else {
+          const auto policy = kPolicyMap.find(trimmed_part);
+          if (policy == kPolicyMap.end()) {
             diag_->Error(DiagMessage(element_source)
                          << "<policy> has unsupported type '" << trimmed_part << "'");
             error = true;
             continue;
           }
+
+          current_policies |= policy->second;
         }
       } else {
         diag_->Error(DiagMessage(element_source)
-                         << "<policy> must have a 'type' attribute");
+                     << "<policy> must have a 'type' attribute");
         error = true;
         continue;
       }
     } else if (!ShouldIgnoreElement(element_namespace, element_name)) {
       diag_->Error(DiagMessage(element_source) << "invalid element <" << element_name << "> "
-                                            << " in <overlayable>");
+                                               << " in <overlayable>");
       error = true;
       break;
     }
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 8577921..7c8b6d0 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -971,6 +971,12 @@
         <policy type="signature">
           <item type="string" name="foz" />
         </policy>
+        <policy type="odm">
+          <item type="string" name="biz" />
+        </policy>
+        <policy type="oem">
+          <item type="string" name="buz" />
+        </policy>
       </overlayable>)";
   ASSERT_TRUE(TestParse(input));
 
@@ -1013,6 +1019,22 @@
   result_overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
   EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature));
+
+  search_result = table_.FindResource(test::ParseNameOrDie("string/biz"));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  ASSERT_TRUE(search_result.value().entry->overlayable_item);
+  result_overlayable_item = search_result.value().entry->overlayable_item.value();
+  EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
+  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kOdm));
+
+  search_result = table_.FindResource(test::ParseNameOrDie("string/buz"));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  ASSERT_TRUE(search_result.value().entry->overlayable_item);
+  result_overlayable_item = search_result.value().entry->overlayable_item.value();
+  EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
+  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kOem));
 }
 
 TEST_F(ResourceParserTest, ParseOverlayableNoPolicyError) {
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index 7ed7897..30ba1ae 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -79,22 +79,28 @@
   // Represents the types overlays that are allowed to overlay the resource.
   typedef uint32_t PolicyFlags;
   enum Policy : uint32_t {
-    kNone = 0x00,
+    kNone = 0x00000000,
 
     // The resource can be overlaid by any overlay.
-    kPublic = 0x01,
+    kPublic = 0x00000001,
 
     // The resource can be overlaid by any overlay on the system partition.
-    kSystem = 0x02,
+    kSystem = 0x00000002,
 
     // The resource can be overlaid by any overlay on the vendor partition.
-    kVendor = 0x04,
+    kVendor = 0x00000004,
 
     // The resource can be overlaid by any overlay on the product partition.
-    kProduct = 0x08,
+    kProduct = 0x00000008,
 
     // The resource can be overlaid by any overlay signed with the same signature as its actor.
-    kSignature = 0x010,
+    kSignature = 0x00000010,
+
+    // The resource can be overlaid by any overlay on the odm partition.
+    kOdm = 0x00000020,
+
+    // The resource can be overlaid by any overlay on the oem partition.
+    kOem = 0x00000040,
   };
 
   std::shared_ptr<Overlayable> overlayable;
diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto
index a2fd7c6..12cf65b 100644
--- a/tools/aapt2/Resources.proto
+++ b/tools/aapt2/Resources.proto
@@ -157,6 +157,8 @@
     VENDOR = 3;
     PRODUCT = 4;
     SIGNATURE = 5;
+    ODM = 6;
+    OEM = 7;
   }
 
   // The location of the <item> declaration in source.
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index 59eb9ec2..fd8e36e 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -475,6 +475,14 @@
           & ResTable_overlayable_policy_header::POLICY_SIGNATURE) {
         policies |= OverlayableItem::Policy::kSignature;
       }
+      if (policy_header->policy_flags
+          & ResTable_overlayable_policy_header::POLICY_ODM_PARTITION) {
+        policies |= OverlayableItem::Policy::kOdm;
+      }
+      if (policy_header->policy_flags
+          & ResTable_overlayable_policy_header::POLICY_OEM_PARTITION) {
+        policies |= OverlayableItem::Policy::kOem;
+      }
 
       const ResTable_ref* const ref_begin = reinterpret_cast<const ResTable_ref*>(
           ((uint8_t *)policy_header) + util::DeviceToHost32(policy_header->header.headerSize));
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index aa578a2..f2e72da 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -496,6 +496,12 @@
         if (item.policies & OverlayableItem::Policy::kSignature) {
           policy_flags |= ResTable_overlayable_policy_header::POLICY_SIGNATURE;
         }
+        if (item.policies & OverlayableItem::Policy::kOdm) {
+          policy_flags |= ResTable_overlayable_policy_header::POLICY_ODM_PARTITION;
+        }
+        if (item.policies & OverlayableItem::Policy::kOem) {
+          policy_flags |= ResTable_overlayable_policy_header::POLICY_OEM_PARTITION;
+        }
 
         auto policy = overlayable_chunk->policy_ids.find(policy_flags);
         if (policy != overlayable_chunk->policy_ids.end()) {
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index 4c5dbec..a940923 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -724,8 +724,8 @@
 
   std::string name_two = "com.app.test:integer/overlayable_two";
   OverlayableItem overlayable_item_two(group);
-  overlayable_item_two.policies |= OverlayableItem::Policy::kProduct;
-  overlayable_item_two.policies |= OverlayableItem::Policy::kSystem;
+  overlayable_item_two.policies |= OverlayableItem::Policy::kOdm;
+  overlayable_item_two.policies |= OverlayableItem::Policy::kOem;
   overlayable_item_two.policies |= OverlayableItem::Policy::kVendor;
 
   std::string name_three = "com.app.test:integer/overlayable_three";
@@ -744,6 +744,7 @@
           .AddSimple(name_three, ResourceId(0x7f020003))
           .SetOverlayable(name_three, overlayable_item_three)
           .Build();
+
   ResourceTable output_table;
   ASSERT_TRUE(Flatten(context_.get(), {}, table.get(), &output_table));
   auto search_result = output_table.FindResource(test::ParseNameOrDie(name_zero));
@@ -755,6 +756,7 @@
   EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme");
   EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSystem
                                          | OverlayableItem::Policy::kProduct);
+
   search_result = output_table.FindResource(test::ParseNameOrDie(name_one));
   ASSERT_TRUE(search_result);
   ASSERT_THAT(search_result.value().entry, NotNull());
@@ -763,6 +765,7 @@
   EXPECT_EQ(result_overlayable.overlayable->name, "OtherName");
   EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization");
   EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic);
+
   search_result = output_table.FindResource(test::ParseNameOrDie(name_two));
   ASSERT_TRUE(search_result);
   ASSERT_THAT(search_result.value().entry, NotNull());
@@ -770,9 +773,10 @@
   result_overlayable = search_result.value().entry->overlayable_item.value();
   EXPECT_EQ(result_overlayable.overlayable->name, "TestName");
   EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme");
-  EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSystem
-                                         | OverlayableItem::Policy::kProduct
+  EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kOdm
+                                         | OverlayableItem::Policy::kOem
                                          | OverlayableItem::Policy::kVendor);
+
   search_result = output_table.FindResource(test::ParseNameOrDie(name_three));
   ASSERT_TRUE(search_result);
   ASSERT_THAT(search_result.value().entry, NotNull());
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index 06f1bf7..bb21c1c 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -393,6 +393,12 @@
       case pb::OverlayableItem::SIGNATURE:
         out_overlayable->policies |= OverlayableItem::Policy::kSignature;
         break;
+      case pb::OverlayableItem::ODM:
+        out_overlayable->policies |= OverlayableItem::Policy::kOdm;
+        break;
+      case pb::OverlayableItem::OEM:
+        out_overlayable->policies |= OverlayableItem::Policy::kOem;
+        break;
       default:
         *out_error = "unknown overlayable policy";
         return false;
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index eb2b1a2..58e1e6e 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -312,6 +312,12 @@
   if (overlayable_item.policies & OverlayableItem::Policy::kSignature) {
     pb_overlayable_item->add_policy(pb::OverlayableItem::SIGNATURE);
   }
+  if (overlayable_item.policies & OverlayableItem::Policy::kOdm) {
+    pb_overlayable_item->add_policy(pb::OverlayableItem::ODM);
+  }
+  if (overlayable_item.policies & OverlayableItem::Policy::kOem) {
+    pb_overlayable_item->add_policy(pb::OverlayableItem::OEM);
+  }
 
   SerializeSourceToPb(overlayable_item.source, source_pool,
                       pb_overlayable_item->mutable_source());
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index d369ac4..f252f33 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -529,6 +529,8 @@
   OverlayableItem overlayable_item_boz(std::make_shared<Overlayable>(
       "IconPack", "overlay://theme"));
   overlayable_item_boz.policies |= OverlayableItem::Policy::kSignature;
+  overlayable_item_boz.policies |= OverlayableItem::Policy::kOdm;
+  overlayable_item_boz.policies |= OverlayableItem::Policy::kOem;
 
   OverlayableItem overlayable_item_biz(std::make_shared<Overlayable>(
       "Other", "overlay://customization"));
@@ -587,7 +589,9 @@
   overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(overlayable_item.overlayable->name, Eq("IconPack"));
   EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
-  EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature));
+  EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature
+                                            | OverlayableItem::Policy::kOdm
+                                            | OverlayableItem::Policy::kOem));
 
   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/biz"));
   ASSERT_TRUE(search_result);