Merge changes from topic "heads_up_redesign" into pi-dev

* changes:
  Added new appear and disappear animations for heads up
  Polished the heads up experience
  Removed the heads up scrim and replaced it with more elevation
  Insetting heads up notifications
  Ensured that the heads-up notifications are always rounded
diff --git a/api/current.txt b/api/current.txt
index b8f1324..cfea251 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -40058,6 +40058,7 @@
     method public int getSuppressedVisualEffects();
     method public int getUserSentiment();
     method public boolean isAmbient();
+    method public boolean isSuspended();
     method public boolean matchesInterruptionFilter();
     field public static final int USER_SENTIMENT_NEGATIVE = -1; // 0xffffffff
     field public static final int USER_SENTIMENT_NEUTRAL = 0; // 0x0
@@ -43354,21 +43355,21 @@
   public class ApnSetting implements android.os.Parcelable {
     method public int describeContents();
     method public java.lang.String getApnName();
+    method public int getApnTypeBitmask();
     method public int getAuthType();
     method public java.lang.String getEntryName();
     method public int getId();
-    method public int getMmsPort();
-    method public java.net.InetAddress getMmsProxy();
-    method public java.net.URL getMmsc();
-    method public java.lang.String getMvnoType();
+    method public java.net.InetAddress getMmsProxyAddress();
+    method public int getMmsProxyPort();
+    method public android.net.Uri getMmsc();
+    method public int getMvnoType();
     method public int getNetworkTypeBitmask();
     method public java.lang.String getOperatorNumeric();
     method public java.lang.String getPassword();
-    method public int getPort();
-    method public java.lang.String getProtocol();
-    method public java.net.InetAddress getProxy();
-    method public java.lang.String getRoamingProtocol();
-    method public java.util.List<java.lang.String> getTypes();
+    method public int getProtocol();
+    method public java.net.InetAddress getProxyAddress();
+    method public int getProxyPort();
+    method public int getRoamingProtocol();
     method public java.lang.String getUser();
     method public boolean isEnabled();
     method public void writeToParcel(android.os.Parcel, int);
@@ -43377,46 +43378,45 @@
     field public static final int AUTH_TYPE_PAP = 1; // 0x1
     field public static final int AUTH_TYPE_PAP_OR_CHAP = 3; // 0x3
     field public static final android.os.Parcelable.Creator<android.telephony.data.ApnSetting> CREATOR;
-    field public static final java.lang.String MVNO_TYPE_GID = "gid";
-    field public static final java.lang.String MVNO_TYPE_ICCID = "iccid";
-    field public static final java.lang.String MVNO_TYPE_IMSI = "imsi";
-    field public static final java.lang.String MVNO_TYPE_SPN = "spn";
-    field public static final java.lang.String PROTOCOL_IP = "IP";
-    field public static final java.lang.String PROTOCOL_IPV4V6 = "IPV4V6";
-    field public static final java.lang.String PROTOCOL_IPV6 = "IPV6";
-    field public static final java.lang.String PROTOCOL_PPP = "PPP";
-    field public static final java.lang.String TYPE_ALL = "*";
-    field public static final java.lang.String TYPE_CBS = "cbs";
-    field public static final java.lang.String TYPE_DEFAULT = "default";
-    field public static final java.lang.String TYPE_DUN = "dun";
-    field public static final java.lang.String TYPE_EMERGENCY = "emergency";
-    field public static final java.lang.String TYPE_FOTA = "fota";
-    field public static final java.lang.String TYPE_HIPRI = "hipri";
-    field public static final java.lang.String TYPE_IA = "ia";
-    field public static final java.lang.String TYPE_IMS = "ims";
-    field public static final java.lang.String TYPE_MMS = "mms";
-    field public static final java.lang.String TYPE_SUPL = "supl";
+    field public static final int MVNO_TYPE_GID = 2; // 0x2
+    field public static final int MVNO_TYPE_ICCID = 3; // 0x3
+    field public static final int MVNO_TYPE_IMSI = 1; // 0x1
+    field public static final int MVNO_TYPE_SPN = 0; // 0x0
+    field public static final int PROTOCOL_IP = 0; // 0x0
+    field public static final int PROTOCOL_IPV4V6 = 2; // 0x2
+    field public static final int PROTOCOL_IPV6 = 1; // 0x1
+    field public static final int PROTOCOL_PPP = 3; // 0x3
+    field public static final int TYPE_CBS = 128; // 0x80
+    field public static final int TYPE_DEFAULT = 17; // 0x11
+    field public static final int TYPE_DUN = 8; // 0x8
+    field public static final int TYPE_EMERGENCY = 512; // 0x200
+    field public static final int TYPE_FOTA = 32; // 0x20
+    field public static final int TYPE_HIPRI = 16; // 0x10
+    field public static final int TYPE_IA = 256; // 0x100
+    field public static final int TYPE_IMS = 64; // 0x40
+    field public static final int TYPE_MMS = 2; // 0x2
+    field public static final int TYPE_SUPL = 4; // 0x4
   }
 
   public static class ApnSetting.Builder {
     ctor public ApnSetting.Builder();
     method public android.telephony.data.ApnSetting build();
     method public android.telephony.data.ApnSetting.Builder setApnName(java.lang.String);
+    method public android.telephony.data.ApnSetting.Builder setApnTypeBitmask(int);
     method public android.telephony.data.ApnSetting.Builder setAuthType(int);
     method public android.telephony.data.ApnSetting.Builder setCarrierEnabled(boolean);
     method public android.telephony.data.ApnSetting.Builder setEntryName(java.lang.String);
-    method public android.telephony.data.ApnSetting.Builder setMmsPort(int);
-    method public android.telephony.data.ApnSetting.Builder setMmsProxy(java.net.InetAddress);
-    method public android.telephony.data.ApnSetting.Builder setMmsc(java.net.URL);
-    method public android.telephony.data.ApnSetting.Builder setMvnoType(java.lang.String);
+    method public android.telephony.data.ApnSetting.Builder setMmsProxyAddress(java.net.InetAddress);
+    method public android.telephony.data.ApnSetting.Builder setMmsProxyPort(int);
+    method public android.telephony.data.ApnSetting.Builder setMmsc(android.net.Uri);
+    method public android.telephony.data.ApnSetting.Builder setMvnoType(int);
     method public android.telephony.data.ApnSetting.Builder setNetworkTypeBitmask(int);
     method public android.telephony.data.ApnSetting.Builder setOperatorNumeric(java.lang.String);
     method public android.telephony.data.ApnSetting.Builder setPassword(java.lang.String);
-    method public android.telephony.data.ApnSetting.Builder setPort(int);
-    method public android.telephony.data.ApnSetting.Builder setProtocol(java.lang.String);
-    method public android.telephony.data.ApnSetting.Builder setProxy(java.net.InetAddress);
-    method public android.telephony.data.ApnSetting.Builder setRoamingProtocol(java.lang.String);
-    method public android.telephony.data.ApnSetting.Builder setTypes(java.util.List<java.lang.String>);
+    method public android.telephony.data.ApnSetting.Builder setProtocol(int);
+    method public android.telephony.data.ApnSetting.Builder setProxyAddress(java.net.InetAddress);
+    method public android.telephony.data.ApnSetting.Builder setProxyPort(int);
+    method public android.telephony.data.ApnSetting.Builder setRoamingProtocol(int);
     method public android.telephony.data.ApnSetting.Builder setUser(java.lang.String);
   }
 
diff --git a/api/system-current.txt b/api/system-current.txt
index d1ed86e..038c6ed 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5443,6 +5443,7 @@
 
   public class EuiccManager {
     method public void continueOperation(android.content.Intent, android.os.Bundle);
+    method public void eraseSubscriptions(android.app.PendingIntent);
     method public void getDefaultDownloadableSubscriptionList(android.app.PendingIntent);
     method public void getDownloadableSubscriptionMetadata(android.telephony.euicc.DownloadableSubscription, android.app.PendingIntent);
     method public int getOtaStatus();
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 8b681edd..82274a6 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -239,14 +239,13 @@
     }
 }
 
+/*
+ * onDumpReport dumps serialized ConfigMetricsReportList into outData.
+ */
 void StatsLogProcessor::onDumpReport(const ConfigKey& key, const uint64_t dumpTimeStampNs,
                                      vector<uint8_t>* outData) {
     std::lock_guard<std::mutex> lock(mMetricsMutex);
-    onDumpReportLocked(key, dumpTimeStampNs, outData);
-}
 
-void StatsLogProcessor::onDumpReportLocked(const ConfigKey& key, const uint64_t dumpTimeStampNs,
-                                           vector<uint8_t>* outData) {
     auto it = mMetricsManagers.find(key);
     if (it == mMetricsManagers.end()) {
         ALOGW("Config source %s does not exist", key.ToString().c_str());
@@ -269,35 +268,14 @@
     // Start of ConfigMetricsReport (reports).
     uint64_t reportsToken =
             proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS);
-
-    int64_t lastReportTimeNs = it->second->getLastReportTimeNs();
-    int64_t lastReportWallClockNs = it->second->getLastReportWallClockNs();
-
-    // First, fill in ConfigMetricsReport using current data on memory, which
-    // starts from filling in StatsLogReport's.
-    it->second->onDumpReport(dumpTimeStampNs, &proto);
-
-    // Fill in UidMap.
-    vector<uint8_t> uidMap;
-    mUidMap->getOutput(key, &uidMap);
-    proto.write(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP, uidMap.data());
-
-    // Fill in the timestamps.
-    proto.write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_ELAPSED_NANOS,
-                (long long)lastReportTimeNs);
-    proto.write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS,
-                (long long)dumpTimeStampNs);
-    proto.write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_WALL_CLOCK_NANOS,
-                (long long)lastReportWallClockNs);
-    proto.write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_WALL_CLOCK_NANOS,
-                (long long)getWallClockNs());
-
-    // End of ConfigMetricsReport (reports).
+    onConfigMetricsReportLocked(key, dumpTimeStampNs, &proto);
     proto.end(reportsToken);
+    // End of ConfigMetricsReport (reports).
+
 
     // Then, check stats-data directory to see there's any file containing
     // ConfigMetricsReport from previous shutdowns to concatenate to reports.
-    StorageManager::appendConfigMetricsReport(proto);
+    StorageManager::appendConfigMetricsReport(key, &proto);
 
     if (outData != nullptr) {
         outData->clear();
@@ -315,6 +293,40 @@
     StatsdStats::getInstance().noteMetricsReportSent(key);
 }
 
+/*
+ * onConfigMetricsReportLocked dumps serialized ConfigMetricsReport into outData.
+ */
+void StatsLogProcessor::onConfigMetricsReportLocked(const ConfigKey& key,
+                                                    const uint64_t dumpTimeStampNs,
+                                                    ProtoOutputStream* proto) {
+    // We already checked whether key exists in mMetricsManagers in
+    // WriteDataToDisk.
+    auto it = mMetricsManagers.find(key);
+    int64_t lastReportTimeNs = it->second->getLastReportTimeNs();
+    int64_t lastReportWallClockNs = it->second->getLastReportWallClockNs();
+
+    // First, fill in ConfigMetricsReport using current data on memory, which
+    // starts from filling in StatsLogReport's.
+    it->second->onDumpReport(dumpTimeStampNs, proto);
+
+    // Fill in UidMap.
+    uint64_t uidMapToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP);
+    mUidMap->appendUidMap(key, proto);
+    proto->end(uidMapToken);
+
+    // Fill in the timestamps.
+    proto->write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_ELAPSED_NANOS,
+                (long long)lastReportTimeNs);
+    proto->write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS,
+                (long long)dumpTimeStampNs);
+    proto->write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_WALL_CLOCK_NANOS,
+                (long long)lastReportWallClockNs);
+    proto->write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_WALL_CLOCK_NANOS,
+                (long long)getWallClockNs());
+
+
+}
+
 void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) {
     std::lock_guard<std::mutex> lock(mMetricsMutex);
     auto it = mMetricsManagers.find(key);
@@ -368,11 +380,17 @@
     std::lock_guard<std::mutex> lock(mMetricsMutex);
     for (auto& pair : mMetricsManagers) {
         const ConfigKey& key = pair.first;
-        vector<uint8_t> data;
-        onDumpReportLocked(key, getElapsedRealtimeNs(), &data);
+        ProtoOutputStream proto;
+        onConfigMetricsReportLocked(key, getElapsedRealtimeNs(), &proto);
         string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR,
              (long)getWallClockSec(), key.GetUid(), (long long)key.GetId());
-        StorageManager::writeFile(file_name.c_str(), &data[0], data.size());
+        android::base::unique_fd fd(open(file_name.c_str(),
+                                    O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR));
+        if (fd == -1) {
+            VLOG("Attempt to write %s but failed", file_name.c_str());
+            return;
+        }
+        proto.flush(fd.get());
     }
 }
 
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 8b42146..1be4dc5 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -86,8 +86,8 @@
 
     sp<AlarmMonitor> mPeriodicAlarmMonitor;
 
-    void onDumpReportLocked(const ConfigKey& key, const uint64_t dumpTimeNs,
-                            vector<uint8_t>* outData);
+    void onConfigMetricsReportLocked(const ConfigKey& key, const uint64_t dumpTimeStampNs,
+                                     util::ProtoOutputStream* proto);
 
     /* Check if we should send a broadcast if approaching memory limits and if we're over, we
      * actually delete the data. */
diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
index 72a00cb..fb0be73 100644
--- a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
+++ b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
@@ -166,6 +166,11 @@
     // Round it to the nearest minutes. This is the limit of alarm manager.
     // In practice, we should limit it higher.
     long roundedIntervalMs = intervalMs/1000/60 * 1000 * 60;
+    // Scheduled pulling should be at least 1 min apart.
+    // This can be lower in cts tests, in which case we round it to 1 min.
+    if (roundedIntervalMs < 60 * 1000) {
+        roundedIntervalMs = 60 * 1000;
+    }
     // There is only one alarm for all pulled events. So only set it to the smallest denom.
     if (roundedIntervalMs < mCurrentPullingInterval) {
         VLOG("Updating pulling interval %ld", intervalMs);
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index e97d8b2..3ba4b7a 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -331,25 +331,25 @@
     return mBytesUsed;
 }
 
-void UidMap::getOutput(const ConfigKey& key, vector<uint8_t>* outData) {
-    getOutput(getElapsedRealtimeNs(), key, outData);
+void UidMap::appendUidMap(const ConfigKey& key, ProtoOutputStream* proto) {
+    appendUidMap(getElapsedRealtimeNs(), key, proto);
 }
 
-void UidMap::getOutput(const int64_t& timestamp, const ConfigKey& key, vector<uint8_t>* outData) {
+void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key,
+                          ProtoOutputStream* proto) {
     lock_guard<mutex> lock(mMutex);  // Lock for updates
 
-    ProtoOutputStream proto;
     for (const ChangeRecord& record : mChanges) {
         if (record.timestampNs > mLastUpdatePerConfigKey[key]) {
             uint64_t changesToken =
-                    proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_CHANGES);
-            proto.write(FIELD_TYPE_BOOL | FIELD_ID_CHANGE_DELETION, (bool)record.deletion);
-            proto.write(FIELD_TYPE_INT64 | FIELD_ID_CHANGE_TIMESTAMP,
-                        (long long)record.timestampNs);
-            proto.write(FIELD_TYPE_STRING | FIELD_ID_CHANGE_PACKAGE, record.package);
-            proto.write(FIELD_TYPE_INT32 | FIELD_ID_CHANGE_UID, (int)record.uid);
-            proto.write(FIELD_TYPE_INT32 | FIELD_ID_CHANGE_VERSION, (int)record.version);
-            proto.end(changesToken);
+                    proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_CHANGES);
+            proto->write(FIELD_TYPE_BOOL | FIELD_ID_CHANGE_DELETION, (bool)record.deletion);
+            proto->write(FIELD_TYPE_INT64 | FIELD_ID_CHANGE_TIMESTAMP,
+                         (long long)record.timestampNs);
+            proto->write(FIELD_TYPE_STRING | FIELD_ID_CHANGE_PACKAGE, record.package);
+            proto->write(FIELD_TYPE_INT32 | FIELD_ID_CHANGE_UID, (int)record.uid);
+            proto->write(FIELD_TYPE_INT32 | FIELD_ID_CHANGE_VERSION, (int)record.version);
+            proto->end(changesToken);
         }
     }
 
@@ -360,13 +360,13 @@
         if ((count == mSnapshots.size() - 1 && !atLeastOneSnapshot) ||
             record.timestampNs > mLastUpdatePerConfigKey[key]) {
             uint64_t snapshotsToken =
-                    proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_SNAPSHOTS);
+                    proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_SNAPSHOTS);
             atLeastOneSnapshot = true;
             count++;
-            proto.write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_TIMESTAMP,
-                        (long long)record.timestampNs);
-            proto.write(FIELD_TYPE_MESSAGE | FIELD_ID_SNAPSHOT_PACKAGE_INFO, record.bytes.data());
-            proto.end(snapshotsToken);
+            proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_TIMESTAMP,
+                         (long long)record.timestampNs);
+            proto->write(FIELD_TYPE_MESSAGE | FIELD_ID_SNAPSHOT_PACKAGE_INFO, record.bytes.data());
+            proto->end(snapshotsToken);
         }
     }
 
@@ -398,47 +398,36 @@
             // Produce another snapshot. This results in extra data being uploaded but
             // helps ensure we can re-construct the UID->app name, versionCode mapping
             // in server.
-            ProtoOutputStream proto;
-            uint64_t token = proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                          FIELD_ID_SNAPSHOT_PACKAGE_INFO);
+            ProtoOutputStream snapshotProto;
+            uint64_t token = snapshotProto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+                                                 FIELD_ID_SNAPSHOT_PACKAGE_INFO);
             for (const auto& it : mMap) {
-                proto.write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME,
-                            it.second.packageName);
-                proto.write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION,
-                            (int)it.second.versionCode);
-                proto.write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_UID, (int)it.first);
+                snapshotProto.write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME,
+                                    it.second.packageName);
+                snapshotProto.write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION,
+                                    (int)it.second.versionCode);
+                snapshotProto.write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_UID,
+                                    (int)it.first);
             }
-            proto.end(token);
+            snapshotProto.end(token);
 
             // Copy ProtoOutputStream output to
-            auto iter = proto.data();
-            vector<char> outData(proto.size());
+            auto iter = snapshotProto.data();
+            vector<char> snapshotData(snapshotProto.size());
             size_t pos = 0;
             while (iter.readBuffer() != NULL) {
                 size_t toRead = iter.currentToRead();
-                std::memcpy(&(outData[pos]), iter.readBuffer(), toRead);
+                std::memcpy(&(snapshotData[pos]), iter.readBuffer(), toRead);
                 pos += toRead;
                 iter.rp()->move(toRead);
             }
-            mSnapshots.emplace_back(timestamp, outData);
-            mBytesUsed += kBytesTimestampField + outData.size();
+            mSnapshots.emplace_back(timestamp, snapshotData);
+            mBytesUsed += kBytesTimestampField + snapshotData.size();
         }
     }
     StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
     StatsdStats::getInstance().setUidMapChanges(mChanges.size());
     StatsdStats::getInstance().setUidMapSnapshots(mSnapshots.size());
-    if (outData != nullptr) {
-        outData->clear();
-        outData->resize(proto.size());
-        size_t pos = 0;
-        auto iter = proto.data();
-        while (iter.readBuffer() != NULL) {
-            size_t toRead = iter.currentToRead();
-            std::memcpy(&((*outData)[pos]), iter.readBuffer(), toRead);
-            pos += toRead;
-            iter.rp()->move(toRead);
-        }
-    }
 }
 
 void UidMap::printUidMap(FILE* out) const {
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index b0181f7..9dc73f4 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -19,6 +19,7 @@
 #include "config/ConfigKey.h"
 #include "config/ConfigListener.h"
 #include "packages/PackageInfoListener.h"
+#include "stats_util.h"
 
 #include <binder/IResultReceiver.h>
 #include <binder/IShellCallback.h>
@@ -32,8 +33,11 @@
 #include <string>
 #include <unordered_map>
 
+using namespace android;
 using namespace std;
 
+using android::util::ProtoOutputStream;
+
 namespace android {
 namespace os {
 namespace statsd {
@@ -45,8 +49,8 @@
     AppData(const string& a, const int64_t v) : packageName(a), versionCode(v){};
 };
 
-// When calling getOutput, we retrieve all the ChangeRecords since the last
-// timestamp we called getOutput for this configuration key.
+// When calling appendUidMap, we retrieve all the ChangeRecords since the last
+// timestamp we called appendUidMap for this configuration key.
 struct ChangeRecord {
     const bool deletion;
     const int64_t timestampNs;
@@ -70,8 +74,8 @@
 // less because of varint encoding).
 const unsigned int kBytesTimestampField = 10;
 
-// When calling getOutput, we retrieve all the snapshots since the last
-// timestamp we called getOutput for this configuration key.
+// When calling appendUidMap, we retrieve all the snapshots since the last
+// timestamp we called appendUidMap for this configuration key.
 struct SnapshotRecord {
     const int64_t timestampNs;
 
@@ -135,7 +139,7 @@
     // Gets all snapshots and changes that have occurred since the last output.
     // If every config key has received a change or snapshot record, then this
     // record is deleted.
-    void getOutput(const ConfigKey& key, vector<uint8_t>* outData);
+    void appendUidMap(const ConfigKey& key, util::ProtoOutputStream* proto);
 
     // Forces the output to be cleared. We still generate a snapshot based on the current state.
     // This results in extra data uploaded but helps us reconstruct the uid mapping on the server
@@ -158,7 +162,8 @@
                    const int64_t& versionCode);
     void removeApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid);
 
-    void getOutput(const int64_t& timestamp, const ConfigKey& key, vector<uint8_t>* outData);
+    void appendUidMap(const int64_t& timestamp, const ConfigKey& key,
+                      util::ProtoOutputStream* proto);
 
     void getListenerListCopyLocked(std::vector<wp<PackageInfoListener>>* output);
 
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index cd41f53..3d8aa47 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -160,38 +160,46 @@
     }
 }
 
-void StorageManager::appendConfigMetricsReport(ProtoOutputStream& proto) {
+void StorageManager::appendConfigMetricsReport(const ConfigKey& key, ProtoOutputStream* proto) {
     unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_DATA_DIR), closedir);
     if (dir == NULL) {
         VLOG("Path %s does not exist", STATS_DATA_DIR);
         return;
     }
 
+    const char* suffix =
+            StringPrintf("%d_%lld", key.GetUid(), (long long)key.GetId()).c_str();
+
     dirent* de;
     while ((de = readdir(dir.get()))) {
         char* name = de->d_name;
         if (name[0] == '.') continue;
-        VLOG("file %s", name);
 
-        int64_t result[3];
-        parseFileName(name, result);
-        if (result[0] == -1) continue;
-        int64_t timestamp = result[0];
-        int64_t uid = result[1];
-        int64_t configID = result[2];
-        string file_name = getFilePath(STATS_DATA_DIR, timestamp, uid, configID);
-        int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
-        if (fd != -1) {
-            string content;
-            if (android::base::ReadFdToString(fd, &content)) {
-                proto.write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS,
-                            content.c_str());
+        size_t nameLen = strlen(name);
+        size_t suffixLen = strlen(suffix);
+        if (suffixLen <= nameLen &&
+                strncmp(name + nameLen - suffixLen, suffix, suffixLen) == 0) {
+            int64_t result[3];
+            parseFileName(name, result);
+            if (result[0] == -1) continue;
+            int64_t timestamp = result[0];
+            int64_t uid = result[1];
+            int64_t configID = result[2];
+
+            string file_name = getFilePath(STATS_DATA_DIR, timestamp, uid, configID);
+            int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
+            if (fd != -1) {
+                string content;
+                if (android::base::ReadFdToString(fd, &content)) {
+                    proto->write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS,
+                                content.c_str(), content.size());
+                }
+                close(fd);
             }
-            close(fd);
-        }
 
-        // Remove file from disk after reading.
-        remove(file_name.c_str());
+            // Remove file from disk after reading.
+            remove(file_name.c_str());
+        }
     }
 }
 
@@ -275,9 +283,11 @@
                 if (android::base::ReadFdToString(fd, &content)) {
                     vector<uint8_t> vec(content.begin(), content.end());
                     if (vec == config) {
+                        close(fd);
                         return true;
                     }
                 }
+                close(fd);
             }
         }
     }
diff --git a/cmds/statsd/src/storage/StorageManager.h b/cmds/statsd/src/storage/StorageManager.h
index 4b75628..fb7b085 100644
--- a/cmds/statsd/src/storage/StorageManager.h
+++ b/cmds/statsd/src/storage/StorageManager.h
@@ -66,7 +66,7 @@
      * Appends ConfigMetricsReport found on disk to the specific proto and
      * delete it.
      */
-    static void appendConfigMetricsReport(ProtoOutputStream& proto);
+    static void appendConfigMetricsReport(const ConfigKey& key, ProtoOutputStream* proto);
 
     /**
      * Call to load the saved configs from disk.
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index ee7d770..c9492eb 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -20,6 +20,7 @@
 #include "statslog.h"
 #include "statsd_test_util.h"
 
+#include <android/util/ProtoOutputStream.h>
 #include <gtest/gtest.h>
 
 #include <stdio.h>
@@ -30,6 +31,8 @@
 namespace os {
 namespace statsd {
 
+using android::util::ProtoOutputStream;
+
 #ifdef __ANDROID__
 const string kApp1 = "app1.sharing.1";
 const string kApp2 = "app2.sharing.1";
@@ -156,6 +159,20 @@
     EXPECT_TRUE(name_set.find("new_app1_name") != name_set.end());
 }
 
+static void protoOutputStreamToUidMapping(ProtoOutputStream* proto, UidMapping* results) {
+    vector<uint8_t> bytes;
+    bytes.resize(proto->size());
+    size_t pos = 0;
+    auto iter = proto->data();
+    while (iter.readBuffer() != NULL) {
+        size_t toRead = iter.currentToRead();
+        std::memcpy(&((bytes)[pos]), iter.readBuffer(), toRead);
+        pos += toRead;
+        iter.rp()->move(toRead);
+    }
+    results->ParseFromArray(bytes.data(), bytes.size());
+}
+
 TEST(UidMapTest, TestClearingOutput) {
     UidMap m;
 
@@ -176,26 +193,26 @@
     m.updateMap(1, uids, versions, apps);
     EXPECT_EQ(1U, m.mSnapshots.size());
 
-    vector<uint8_t> bytes;
-    m.getOutput(2, config1, &bytes);
+    ProtoOutputStream proto;
+    m.appendUidMap(2, config1, &proto);
     UidMapping results;
-    results.ParseFromArray(bytes.data(), bytes.size());
+    protoOutputStreamToUidMapping(&proto, &results);
     EXPECT_EQ(1, results.snapshots_size());
 
     // It should be cleared now
     EXPECT_EQ(1U, m.mSnapshots.size());
-    bytes.clear();
-    m.getOutput(2, config1, &bytes);
-    results.ParseFromArray(bytes.data(), bytes.size());
+    proto.clear();
+    m.appendUidMap(2, config1, &proto);
+    protoOutputStreamToUidMapping(&proto, &results);
     EXPECT_EQ(1, results.snapshots_size());
 
     // Now add another configuration.
     m.OnConfigUpdated(config2);
     m.updateApp(5, String16(kApp1.c_str()), 1000, 40);
     EXPECT_EQ(1U, m.mChanges.size());
-    bytes.clear();
-    m.getOutput(6, config1, &bytes);
-    results.ParseFromArray(bytes.data(), bytes.size());
+    proto.clear();
+    m.appendUidMap(6, config1, &proto);
+    protoOutputStreamToUidMapping(&proto, &results);
     EXPECT_EQ(1, results.snapshots_size());
     EXPECT_EQ(1, results.changes_size());
     EXPECT_EQ(1U, m.mChanges.size());
@@ -205,16 +222,16 @@
     EXPECT_EQ(2U, m.mChanges.size());
 
     // We still can't remove anything.
-    bytes.clear();
-    m.getOutput(8, config1, &bytes);
-    results.ParseFromArray(bytes.data(), bytes.size());
+    proto.clear();
+    m.appendUidMap(8, config1, &proto);
+    protoOutputStreamToUidMapping(&proto, &results);
     EXPECT_EQ(1, results.snapshots_size());
     EXPECT_EQ(1, results.changes_size());
     EXPECT_EQ(2U, m.mChanges.size());
 
-    bytes.clear();
-    m.getOutput(9, config2, &bytes);
-    results.ParseFromArray(bytes.data(), bytes.size());
+    proto.clear();
+    m.appendUidMap(9, config2, &proto);
+    protoOutputStreamToUidMapping(&proto, &results);
     EXPECT_EQ(1, results.snapshots_size());
     EXPECT_EQ(2, results.changes_size());
     // At this point both should be cleared.
@@ -242,11 +259,12 @@
     m.updateApp(3, String16(kApp1.c_str()), 1000, 40);
     EXPECT_TRUE(m.mBytesUsed > snapshot_bytes);
 
+    ProtoOutputStream proto;
     vector<uint8_t> bytes;
-    m.getOutput(2, config1, &bytes);
+    m.appendUidMap(2, config1, &proto);
     size_t prevBytes = m.mBytesUsed;
 
-    m.getOutput(4, config1, &bytes);
+    m.appendUidMap(4, config1, &proto);
     EXPECT_TRUE(m.mBytesUsed < prevBytes);
 }
 
@@ -286,4 +304,4 @@
 
 }  // namespace statsd
 }  // namespace os
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 833b0f7..1d069bc 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -30,12 +30,15 @@
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
 import android.app.backup.BackupAgent;
+import android.app.servertransaction.ActivityLifecycleItem;
 import android.app.servertransaction.ActivityLifecycleItem.LifecycleState;
+import android.app.servertransaction.ActivityRelaunchItem;
 import android.app.servertransaction.ActivityResultItem;
 import android.app.servertransaction.ClientTransaction;
 import android.app.servertransaction.PendingTransactionActions;
 import android.app.servertransaction.PendingTransactionActions.StopInfo;
 import android.app.servertransaction.TransactionExecutor;
+import android.app.servertransaction.TransactionExecutorHelper;
 import android.content.BroadcastReceiver;
 import android.content.ComponentCallbacks2;
 import android.content.ComponentName;
@@ -520,6 +523,10 @@
             return activityInfo.persistableMode == ActivityInfo.PERSIST_ACROSS_REBOOTS;
         }
 
+        public boolean isVisibleFromServer() {
+            return activity != null && activity.mVisibleFromServer;
+        }
+
         public String toString() {
             ComponentName componentName = intent != null ? intent.getComponent() : null;
             return "ActivityRecord{"
@@ -1797,6 +1804,7 @@
                         // message is handled.
                         transaction.recycle();
                     }
+                    // TODO(lifecycler): Recycle locally scheduled transactions.
                     break;
             }
             Object obj = msg.obj;
@@ -4723,14 +4731,25 @@
             return;
         }
 
-        // TODO(b/73747058): Investigate converting this to use transaction to relaunch.
-        handleRelaunchActivityInner(r, 0 /* configChanges */, null /* pendingResults */,
-                null /* pendingIntents */, null /* pendingActions */, prevState != ON_RESUME,
-                r.overrideConfig, "handleRelaunchActivityLocally");
 
-        // Restore back to the previous state before relaunch if needed.
-        if (prevState != r.getLifecycleState()) {
-            mTransactionExecutor.cycleToPath(r, prevState);
+        // Initialize a relaunch request.
+        final MergedConfiguration mergedConfiguration = new MergedConfiguration(
+                r.createdConfig != null ? r.createdConfig : mConfiguration,
+                r.overrideConfig);
+        final ActivityRelaunchItem activityRelaunchItem = ActivityRelaunchItem.obtain(
+                null /* pendingResults */, null /* pendingIntents */, 0 /* configChanges */,
+                mergedConfiguration, r.mPreserveWindow);
+        // Make sure to match the existing lifecycle state in the end of the transaction.
+        final ActivityLifecycleItem lifecycleRequest =
+                TransactionExecutorHelper.getLifecycleRequestForCurrentState(r);
+        // Schedule the transaction.
+        final ClientTransaction transaction = ClientTransaction.obtain(this.mAppThread, r.token);
+        transaction.addCallback(activityRelaunchItem);
+        transaction.setLifecycleStateRequest(lifecycleRequest);
+        try {
+            mAppThread.scheduleTransaction(transaction);
+        } catch (RemoteException e) {
+            // Local scheduling
         }
     }
 
diff --git a/core/java/android/app/servertransaction/TransactionExecutorHelper.java b/core/java/android/app/servertransaction/TransactionExecutorHelper.java
index 7e66fd7..01b13a2 100644
--- a/core/java/android/app/servertransaction/TransactionExecutorHelper.java
+++ b/core/java/android/app/servertransaction/TransactionExecutorHelper.java
@@ -26,7 +26,7 @@
 import static android.app.servertransaction.ActivityLifecycleItem.PRE_ON_CREATE;
 import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED;
 
-import android.app.ActivityThread;
+import android.app.ActivityThread.ActivityClientRecord;
 import android.util.IntArray;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -124,7 +124,7 @@
      *         {@link ActivityLifecycleItem#UNDEFINED} if there is not path.
      */
     @VisibleForTesting
-    public int getClosestPreExecutionState(ActivityThread.ActivityClientRecord r,
+    public int getClosestPreExecutionState(ActivityClientRecord r,
             int postExecutionState) {
         switch (postExecutionState) {
             case UNDEFINED:
@@ -147,7 +147,7 @@
      *         were provided or there is not path.
      */
     @VisibleForTesting
-    public int getClosestOfStates(ActivityThread.ActivityClientRecord r, int[] finalStates) {
+    public int getClosestOfStates(ActivityClientRecord r, int[] finalStates) {
         if (finalStates == null || finalStates.length == 0) {
             return UNDEFINED;
         }
@@ -168,6 +168,27 @@
         return closestState;
     }
 
+    /** Get the lifecycle state request to match the current state in the end of a transaction. */
+    public static ActivityLifecycleItem getLifecycleRequestForCurrentState(ActivityClientRecord r) {
+        final int prevState = r.getLifecycleState();
+        final ActivityLifecycleItem lifecycleItem;
+        switch (prevState) {
+            // TODO(lifecycler): Extend to support all possible states.
+            case ON_PAUSE:
+                lifecycleItem = PauseActivityItem.obtain();
+                break;
+            case ON_STOP:
+                lifecycleItem = StopActivityItem.obtain(r.isVisibleFromServer(),
+                        0 /* configChanges */);
+                break;
+            default:
+                lifecycleItem = ResumeActivityItem.obtain(false /* isForward */);
+                break;
+        }
+
+        return lifecycleItem;
+    }
+
     /**
      * Check if there is a destruction involved in the path. We want to avoid a lifecycle sequence
      * that involves destruction and recreation if there is another path.
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 59f001c..1c384580 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -107,25 +107,35 @@
     public static final int STANDBY_BUCKET_EXEMPTED = 5;
 
     /**
-     * The app was used very recently, currently in use or likely to be used very soon.
+     * The app was used very recently, currently in use or likely to be used very soon. Standby
+     * bucket values that are &le; {@link #STANDBY_BUCKET_ACTIVE} will not be throttled by the
+     * system while they are in this bucket. Buckets &gt; {@link #STANDBY_BUCKET_ACTIVE} will most
+     * likely be restricted in some way. For instance, jobs and alarms may be deferred.
      * @see #getAppStandbyBucket()
      */
     public static final int STANDBY_BUCKET_ACTIVE = 10;
 
     /**
-     * The app was used recently and/or likely to be used in the next few hours.
+     * The app was used recently and/or likely to be used in the next few hours. Restrictions will
+     * apply to these apps, such as deferral of jobs and alarms.
      * @see #getAppStandbyBucket()
      */
     public static final int STANDBY_BUCKET_WORKING_SET = 20;
 
     /**
      * The app was used in the last few days and/or likely to be used in the next few days.
+     * Restrictions will apply to these apps, such as deferral of jobs and alarms. The delays may be
+     * greater than for apps in higher buckets (lower bucket value). Bucket values &gt;
+     * {@link #STANDBY_BUCKET_FREQUENT} may additionally have network access limited.
      * @see #getAppStandbyBucket()
      */
     public static final int STANDBY_BUCKET_FREQUENT = 30;
 
     /**
      * The app has not be used for several days and/or is unlikely to be used for several days.
+     * Apps in this bucket will have the most restrictions, including network restrictions, except
+     * during certain short periods (at a minimum, once a day) when they are allowed to execute
+     * jobs, access the network, etc.
      * @see #getAppStandbyBucket()
      */
     public static final int STANDBY_BUCKET_RARE = 40;
@@ -393,11 +403,19 @@
     /**
      * Returns the current standby bucket of the calling app. The system determines the standby
      * state of the app based on app usage patterns. Standby buckets determine how much an app will
-     * be restricted from running background tasks such as jobs, alarms and certain PendingIntent
-     * callbacks.
+     * be restricted from running background tasks such as jobs and alarms.
      * <p>Restrictions increase progressively from {@link #STANDBY_BUCKET_ACTIVE} to
      * {@link #STANDBY_BUCKET_RARE}, with {@link #STANDBY_BUCKET_ACTIVE} being the least
      * restrictive. The battery level of the device might also affect the restrictions.
+     * <p>Apps in buckets &le; {@link #STANDBY_BUCKET_ACTIVE} have no standby restrictions imposed.
+     * Apps in buckets &gt; {@link #STANDBY_BUCKET_FREQUENT} may have network access restricted when
+     * running in the background.
+     * <p>The standby state of an app can change at any time either due to a user interaction or a
+     * system interaction or some algorithm determining that the app can be restricted for a period
+     * of time before the user has a need for it.
+     * <p>You can also query the recent history of standby bucket changes by calling
+     * {@link #queryEventsForSelf(long, long)} and searching for
+     * {@link UsageEvents.Event#STANDBY_BUCKET_CHANGED}.
      *
      * @return the current standby bucket of the calling app. One of STANDBY_BUCKET_* constants.
      */
diff --git a/core/java/android/security/backup/TrustedRootCertificates.java b/core/java/android/security/keystore/recovery/TrustedRootCertificates.java
similarity index 96%
rename from core/java/android/security/backup/TrustedRootCertificates.java
rename to core/java/android/security/keystore/recovery/TrustedRootCertificates.java
index ed922ed..27c6522 100644
--- a/core/java/android/security/backup/TrustedRootCertificates.java
+++ b/core/java/android/security/keystore/recovery/TrustedRootCertificates.java
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package android.security.backup;
+package android.security.keystore.recovery;
 
-import static android.security.backup.X509CertificateParsingUtils.decodeBase64Cert;
+import static android.security.keystore.recovery.X509CertificateParsingUtils.decodeBase64Cert;
 
 import android.util.ArrayMap;
 
diff --git a/core/java/android/security/backup/X509CertificateParsingUtils.java b/core/java/android/security/keystore/recovery/X509CertificateParsingUtils.java
similarity index 98%
rename from core/java/android/security/backup/X509CertificateParsingUtils.java
rename to core/java/android/security/keystore/recovery/X509CertificateParsingUtils.java
index 30495de..fa72c83 100644
--- a/core/java/android/security/backup/X509CertificateParsingUtils.java
+++ b/core/java/android/security/keystore/recovery/X509CertificateParsingUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.security.backup;
+package android.security.keystore.recovery;
 
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index ea10ae7..3726e66 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1418,6 +1418,7 @@
         private ArrayList<SnoozeCriterion> mSnoozeCriteria;
         private boolean mShowBadge;
         private @UserSentiment int mUserSentiment = USER_SENTIMENT_NEUTRAL;
+        private boolean mHidden;
 
         public Ranking() {}
 
@@ -1557,6 +1558,16 @@
         }
 
         /**
+         * Returns whether the app that posted this notification is suspended, so this notification
+         * should be hidden.
+         *
+         * @return true if the notification should be hidden, false otherwise.
+         */
+        public boolean isSuspended() {
+            return mHidden;
+        }
+
+        /**
          * @hide
          */
         @VisibleForTesting
@@ -1565,7 +1576,7 @@
                 CharSequence explanation, String overrideGroupKey,
                 NotificationChannel channel, ArrayList<String> overridePeople,
                 ArrayList<SnoozeCriterion> snoozeCriteria, boolean showBadge,
-                int userSentiment) {
+                int userSentiment, boolean hidden) {
             mKey = key;
             mRank = rank;
             mIsAmbient = importance < NotificationManager.IMPORTANCE_LOW;
@@ -1580,6 +1591,7 @@
             mSnoozeCriteria = snoozeCriteria;
             mShowBadge = showBadge;
             mUserSentiment = userSentiment;
+            mHidden = hidden;
         }
 
         /**
@@ -1628,6 +1640,7 @@
         private ArrayMap<String, ArrayList<SnoozeCriterion>> mSnoozeCriteria;
         private ArrayMap<String, Boolean> mShowBadge;
         private ArrayMap<String, Integer> mUserSentiment;
+        private ArrayMap<String, Boolean> mHidden;
 
         private RankingMap(NotificationRankingUpdate rankingUpdate) {
             mRankingUpdate = rankingUpdate;
@@ -1656,7 +1669,7 @@
                     getVisibilityOverride(key), getSuppressedVisualEffects(key),
                     getImportance(key), getImportanceExplanation(key), getOverrideGroupKey(key),
                     getChannel(key), getOverridePeople(key), getSnoozeCriteria(key),
-                    getShowBadge(key), getUserSentiment(key));
+                    getShowBadge(key), getUserSentiment(key), getHidden(key));
             return rank >= 0;
         }
 
@@ -1784,6 +1797,16 @@
                     ? Ranking.USER_SENTIMENT_NEUTRAL : userSentiment.intValue();
         }
 
+        private boolean getHidden(String key) {
+            synchronized (this) {
+                if (mHidden == null) {
+                    buildHiddenLocked();
+                }
+            }
+            Boolean hidden = mHidden.get(key);
+            return hidden == null ? false : hidden.booleanValue();
+        }
+
         // Locked by 'this'
         private void buildRanksLocked() {
             String[] orderedKeys = mRankingUpdate.getOrderedKeys();
@@ -1892,6 +1915,15 @@
             }
         }
 
+        // Locked by 'this'
+        private void buildHiddenLocked() {
+            Bundle hidden = mRankingUpdate.getHidden();
+            mHidden = new ArrayMap<>(hidden.size());
+            for (String key : hidden.keySet()) {
+                mHidden.put(key, hidden.getBoolean(key));
+            }
+        }
+
         // ----------- Parcelable
 
         @Override
diff --git a/core/java/android/service/notification/NotificationRankingUpdate.java b/core/java/android/service/notification/NotificationRankingUpdate.java
index 6d51db0..00c47ec 100644
--- a/core/java/android/service/notification/NotificationRankingUpdate.java
+++ b/core/java/android/service/notification/NotificationRankingUpdate.java
@@ -36,12 +36,13 @@
     private final Bundle mSnoozeCriteria;
     private final Bundle mShowBadge;
     private final Bundle mUserSentiment;
+    private final Bundle mHidden;
 
     public NotificationRankingUpdate(String[] keys, String[] interceptedKeys,
             Bundle visibilityOverrides, Bundle suppressedVisualEffects,
             int[] importance, Bundle explanation, Bundle overrideGroupKeys,
             Bundle channels, Bundle overridePeople, Bundle snoozeCriteria,
-            Bundle showBadge, Bundle userSentiment) {
+            Bundle showBadge, Bundle userSentiment, Bundle hidden) {
         mKeys = keys;
         mInterceptedKeys = interceptedKeys;
         mVisibilityOverrides = visibilityOverrides;
@@ -54,6 +55,7 @@
         mSnoozeCriteria = snoozeCriteria;
         mShowBadge = showBadge;
         mUserSentiment = userSentiment;
+        mHidden = hidden;
     }
 
     public NotificationRankingUpdate(Parcel in) {
@@ -70,6 +72,7 @@
         mSnoozeCriteria = in.readBundle();
         mShowBadge = in.readBundle();
         mUserSentiment = in.readBundle();
+        mHidden = in.readBundle();
     }
 
     @Override
@@ -91,6 +94,7 @@
         out.writeBundle(mSnoozeCriteria);
         out.writeBundle(mShowBadge);
         out.writeBundle(mUserSentiment);
+        out.writeBundle(mHidden);
     }
 
     public static final Parcelable.Creator<NotificationRankingUpdate> CREATOR
@@ -151,4 +155,8 @@
     public Bundle getUserSentiment() {
         return mUserSentiment;
     }
+
+    public Bundle getHidden() {
+        return mHidden;
+    }
 }
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index 40e84b9..61277e2 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -545,7 +545,7 @@
      */
     public final void unlockUserWithToken(long handle, byte[] token, UserHandle user) {
         UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
-        if (um.isUserUnlocked()) {
+        if (um.isUserUnlocked(user)) {
             Slog.i(TAG, "User already unlocked");
             return;
         }
diff --git a/core/java/android/text/SpannableString.java b/core/java/android/text/SpannableString.java
index 56d0946..afb5df8 100644
--- a/core/java/android/text/SpannableString.java
+++ b/core/java/android/text/SpannableString.java
@@ -16,7 +16,6 @@
 
 package android.text;
 
-
 /**
  * This is the class for text whose content is immutable but to which
  * markup objects can be attached and detached.
@@ -26,12 +25,27 @@
 extends SpannableStringInternal
 implements CharSequence, GetChars, Spannable
 {
+    /**
+     * @param source source object to copy from
+     * @param ignoreNoCopySpan whether to copy NoCopySpans in the {@code source}
+     * @hide
+     */
+    public SpannableString(CharSequence source, boolean ignoreNoCopySpan) {
+        super(source, 0, source.length(), ignoreNoCopySpan);
+    }
+
+    /**
+     * For the backward compatibility reasons, this constructor copies all spans including {@link
+     * android.text.NoCopySpan}.
+     * @param source source text
+     */
     public SpannableString(CharSequence source) {
-        super(source, 0, source.length());
+        this(source, false /* ignoreNoCopySpan */);  // preserve existing NoCopySpan behavior
     }
 
     private SpannableString(CharSequence source, int start, int end) {
-        super(source, start, end);
+        // preserve existing NoCopySpan behavior
+        super(source, start, end, false /* ignoreNoCopySpan */);
     }
 
     public static SpannableString valueOf(CharSequence source) {
diff --git a/core/java/android/text/SpannableStringInternal.java b/core/java/android/text/SpannableStringInternal.java
index 366ec14..5dd1a52 100644
--- a/core/java/android/text/SpannableStringInternal.java
+++ b/core/java/android/text/SpannableStringInternal.java
@@ -26,7 +26,7 @@
 /* package */ abstract class SpannableStringInternal
 {
     /* package */ SpannableStringInternal(CharSequence source,
-                                          int start, int end) {
+                                          int start, int end, boolean ignoreNoCopySpan) {
         if (start == 0 && end == source.length())
             mText = source.toString();
         else
@@ -38,24 +38,37 @@
 
         if (source instanceof Spanned) {
             if (source instanceof SpannableStringInternal) {
-                copySpans((SpannableStringInternal) source, start, end);
+                copySpans((SpannableStringInternal) source, start, end, ignoreNoCopySpan);
             } else {
-                copySpans((Spanned) source, start, end);
+                copySpans((Spanned) source, start, end, ignoreNoCopySpan);
             }
         }
     }
 
     /**
+     * This unused method is left since this is listed in hidden api list.
+     *
+     * Due to backward compatibility reasons, we copy even NoCopySpan by default
+     */
+    /* package */ SpannableStringInternal(CharSequence source, int start, int end) {
+        this(source, start, end, false /* ignoreNoCopySpan */);
+    }
+
+    /**
      * Copies another {@link Spanned} object's spans between [start, end] into this object.
      *
      * @param src Source object to copy from.
      * @param start Start index in the source object.
      * @param end End index in the source object.
+     * @param ignoreNoCopySpan whether to copy NoCopySpans in the {@code source}
      */
-    private final void copySpans(Spanned src, int start, int end) {
+    private void copySpans(Spanned src, int start, int end, boolean ignoreNoCopySpan) {
         Object[] spans = src.getSpans(start, end, Object.class);
 
         for (int i = 0; i < spans.length; i++) {
+            if (ignoreNoCopySpan && spans[i] instanceof NoCopySpan) {
+                continue;
+            }
             int st = src.getSpanStart(spans[i]);
             int en = src.getSpanEnd(spans[i]);
             int fl = src.getSpanFlags(spans[i]);
@@ -76,35 +89,48 @@
      * @param src Source object to copy from.
      * @param start Start index in the source object.
      * @param end End index in the source object.
+     * @param ignoreNoCopySpan copy NoCopySpan for backward compatible reasons.
      */
-    private final void copySpans(SpannableStringInternal src, int start, int end) {
-        if (start == 0 && end == src.length()) {
+    private void copySpans(SpannableStringInternal src, int start, int end,
+            boolean ignoreNoCopySpan) {
+        int count = 0;
+        final int[] srcData = src.mSpanData;
+        final Object[] srcSpans = src.mSpans;
+        final int limit = src.mSpanCount;
+        boolean hasNoCopySpan = false;
+
+        for (int i = 0; i < limit; i++) {
+            int spanStart = srcData[i * COLUMNS + START];
+            int spanEnd = srcData[i * COLUMNS + END];
+            if (isOutOfCopyRange(start, end, spanStart, spanEnd)) continue;
+            if (srcSpans[i] instanceof NoCopySpan) {
+                hasNoCopySpan = true;
+                if (ignoreNoCopySpan) {
+                    continue;
+                }
+            }
+            count++;
+        }
+
+        if (count == 0) return;
+
+        if (!hasNoCopySpan && start == 0 && end == src.length()) {
             mSpans = ArrayUtils.newUnpaddedObjectArray(src.mSpans.length);
             mSpanData = new int[src.mSpanData.length];
             mSpanCount = src.mSpanCount;
             System.arraycopy(src.mSpans, 0, mSpans, 0, src.mSpans.length);
             System.arraycopy(src.mSpanData, 0, mSpanData, 0, mSpanData.length);
         } else {
-            int count = 0;
-            int[] srcData = src.mSpanData;
-            int limit = src.mSpanCount;
-            for (int i = 0; i < limit; i++) {
-                int spanStart = srcData[i * COLUMNS + START];
-                int spanEnd = srcData[i * COLUMNS + END];
-                if (isOutOfCopyRange(start, end, spanStart, spanEnd)) continue;
-                count++;
-            }
-
-            if (count == 0) return;
-
-            Object[] srcSpans = src.mSpans;
             mSpanCount = count;
             mSpans = ArrayUtils.newUnpaddedObjectArray(mSpanCount);
             mSpanData = new int[mSpans.length * COLUMNS];
             for (int i = 0, j = 0; i < limit; i++) {
                 int spanStart = srcData[i * COLUMNS + START];
                 int spanEnd = srcData[i * COLUMNS + END];
-                if (isOutOfCopyRange(start, end, spanStart, spanEnd)) continue;
+                if (isOutOfCopyRange(start, end, spanStart, spanEnd)
+                        || (ignoreNoCopySpan && srcSpans[i] instanceof NoCopySpan)) {
+                    continue;
+                }
                 if (spanStart < start) spanStart = start;
                 if (spanEnd > end) spanEnd = end;
 
@@ -494,6 +520,21 @@
         return hash;
     }
 
+    /**
+     * Following two unused methods are left since these are listed in hidden api list.
+     *
+     * Due to backward compatibility reasons, we copy even NoCopySpan by default
+     */
+    private void copySpans(Spanned src, int start, int end) {
+        copySpans(src, start, end, false);
+    }
+
+    private void copySpans(SpannableStringInternal src, int start, int end) {
+        copySpans(src, start, end, false);
+    }
+
+
+
     private String mText;
     private Object[] mSpans;
     private int[] mSpanData;
diff --git a/core/java/android/text/SpannedString.java b/core/java/android/text/SpannedString.java
index afed221..acee3c5 100644
--- a/core/java/android/text/SpannedString.java
+++ b/core/java/android/text/SpannedString.java
@@ -26,12 +26,27 @@
 extends SpannableStringInternal
 implements CharSequence, GetChars, Spanned
 {
+    /**
+     * @param source source object to copy from
+     * @param ignoreNoCopySpan whether to copy NoCopySpans in the {@code source}
+     * @hide
+     */
+    public SpannedString(CharSequence source, boolean ignoreNoCopySpan) {
+        super(source, 0, source.length(), ignoreNoCopySpan);
+    }
+
+    /**
+     * For the backward compatibility reasons, this constructor copies all spans including {@link
+     * android.text.NoCopySpan}.
+     * @param source source text
+     */
     public SpannedString(CharSequence source) {
-        super(source, 0, source.length());
+        this(source, false /* ignoreNoCopySpan */);  // preserve existing NoCopySpan behavior
     }
 
     private SpannedString(CharSequence source, int start, int end) {
-        super(source, start, end);
+        // preserve existing NoCopySpan behavior
+        super(source, start, end, false /* ignoreNoCopySpan */);
     }
 
     public CharSequence subSequence(int start, int end) {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index b7524fb..7ff4f21 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -566,7 +566,7 @@
      */
     private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
             SurfaceControl parent, int windowType, int ownerUid)
-                    throws OutOfResourcesException {
+                    throws OutOfResourcesException, IllegalArgumentException {
         if (session == null) {
             throw new IllegalArgumentException("session must not be null");
         }
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index a30b2ad..04cb08f 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -116,9 +116,13 @@
     ScopedUtfChars name(env, nameStr);
     sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
     SurfaceControl *parent = reinterpret_cast<SurfaceControl*>(parentObject);
-    sp<SurfaceControl> surface = client->createSurface(
-            String8(name.c_str()), w, h, format, flags, parent, windowType, ownerUid);
-    if (surface == NULL) {
+    sp<SurfaceControl> surface;
+    status_t err = client->createSurfaceChecked(
+            String8(name.c_str()), w, h, format, &surface, flags, parent, windowType, ownerUid);
+    if (err == NAME_NOT_FOUND) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return 0;
+    } else if (err != NO_ERROR) {
         jniThrowException(env, OutOfResourcesException, NULL);
         return 0;
     }
diff --git a/core/tests/coretests/src/android/security/backup/TrustedRootCertificatesTest.java b/core/tests/coretests/src/android/security/keystore/recovery/TrustedRootCertificatesTest.java
similarity index 90%
rename from core/tests/coretests/src/android/security/backup/TrustedRootCertificatesTest.java
rename to core/tests/coretests/src/android/security/keystore/recovery/TrustedRootCertificatesTest.java
index 0f9cb45..3b4ad38 100644
--- a/core/tests/coretests/src/android/security/backup/TrustedRootCertificatesTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/TrustedRootCertificatesTest.java
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package android.security.backup;
+package android.security.keystore.recovery;
 
-import static android.security.backup.TrustedRootCertificates.listRootCertificates;
+import static android.security.keystore.recovery.TrustedRootCertificates.listRootCertificates;
 
 import static org.junit.Assert.assertTrue;
 
diff --git a/core/tests/coretests/src/android/security/backup/X509CertificateParsingUtilsTest.java b/core/tests/coretests/src/android/security/keystore/recovery/X509CertificateParsingUtilsTest.java
similarity index 96%
rename from core/tests/coretests/src/android/security/backup/X509CertificateParsingUtilsTest.java
rename to core/tests/coretests/src/android/security/keystore/recovery/X509CertificateParsingUtilsTest.java
index ad85c25..7f0eb43 100644
--- a/core/tests/coretests/src/android/security/backup/X509CertificateParsingUtilsTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/X509CertificateParsingUtilsTest.java
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package android.security.backup;
+package android.security.keystore.recovery;
 
-import static android.security.backup.X509CertificateParsingUtils.decodeBase64Cert;
+import static android.security.keystore.recovery.X509CertificateParsingUtils.decodeBase64Cert;
 
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
diff --git a/core/tests/coretests/src/android/text/SpannableStringNoCopyTest.java b/core/tests/coretests/src/android/text/SpannableStringNoCopyTest.java
new file mode 100644
index 0000000..c205f96
--- /dev/null
+++ b/core/tests/coretests/src/android/text/SpannableStringNoCopyTest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+
+import android.annotation.NonNull;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.style.QuoteSpan;
+import android.text.style.UnderlineSpan;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SpannableStringNoCopyTest {
+    @Test
+    public void testCopyConstructor_copyNoCopySpans_SpannableStringInternalImpl() {
+        final SpannableString first = new SpannableString("t\nest data");
+        first.setSpan(new QuoteSpan(), 0, 2, Spanned.SPAN_PARAGRAPH);
+        first.setSpan(new NoCopySpan.Concrete(), 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        first.setSpan(new UnderlineSpan(), 0, first.length(), Spanned.SPAN_PRIORITY);
+
+        // By default, copy NoCopySpans
+        final SpannedString copied = new SpannedString(first);
+        final Object[] spans = copied.getSpans(0, copied.length(), Object.class);
+        assertNotNull(spans);
+        assertEquals(3, spans.length);
+    }
+
+    @Test
+    public void testCopyConstructor_doesNotCopyNoCopySpans_SpannableStringInternalImpl() {
+        final SpannableString first = new SpannableString("t\nest data");
+        first.setSpan(new QuoteSpan(), 0, 2, Spanned.SPAN_PARAGRAPH);
+        first.setSpan(new NoCopySpan.Concrete(), 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        first.setSpan(new UnderlineSpan(), 0, first.length(), Spanned.SPAN_PRIORITY);
+
+        // Do not copy NoCopySpan if specified so.
+        final SpannedString copied = new SpannedString(first, false /* copyNoCopySpan */);
+        final Object[] spans = copied.getSpans(0, copied.length(), Object.class);
+        assertNotNull(spans);
+        assertEquals(2, spans.length);
+
+        for (int i = 0; i < spans.length; i++) {
+            assertFalse(spans[i] instanceof NoCopySpan);
+        }
+    }
+
+    @Test
+    public void testCopyConstructor_copyNoCopySpans_OtherSpannableImpl() {
+        final SpannableString first = new SpannableString("t\nest data");
+        first.setSpan(new QuoteSpan(), 0, 2, Spanned.SPAN_PARAGRAPH);
+        first.setSpan(new NoCopySpan.Concrete(), 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        first.setSpan(new UnderlineSpan(), 0, first.length(), Spanned.SPAN_PRIORITY);
+
+        // By default, copy NoCopySpans
+        final SpannedString copied = new SpannedString(new CustomSpannable(first));
+        final Object[] spans = copied.getSpans(0, copied.length(), Object.class);
+        assertNotNull(spans);
+        assertEquals(3, spans.length);
+    }
+
+    @Test
+    public void testCopyConstructor_doesNotCopyNoCopySpans_OtherSpannableImpl() {
+        final SpannableString first = new SpannableString("t\nest data");
+        first.setSpan(new QuoteSpan(), 0, 2, Spanned.SPAN_PARAGRAPH);
+        first.setSpan(new NoCopySpan.Concrete(), 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        first.setSpan(new UnderlineSpan(), 0, first.length(), Spanned.SPAN_PRIORITY);
+
+        // Do not copy NoCopySpan if specified so.
+        final SpannedString copied = new SpannedString(
+                new CustomSpannable(first), false /* copyNoCopySpan */);
+        final Object[] spans = copied.getSpans(0, copied.length(), Object.class);
+        assertNotNull(spans);
+        assertEquals(2, spans.length);
+
+        for (int i = 0; i < spans.length; i++) {
+            assertFalse(spans[i] instanceof NoCopySpan);
+        }
+    }
+
+    // A custom implementation of Spannable.
+    private static class CustomSpannable implements Spannable {
+        private final @NonNull Spannable mText;
+
+        CustomSpannable(@NonNull Spannable text) {
+            mText = text;
+        }
+
+        @Override
+        public void setSpan(Object what, int start, int end, int flags) {
+            mText.setSpan(what, start, end, flags);
+        }
+
+        @Override
+        public void removeSpan(Object what) {
+            mText.removeSpan(what);
+        }
+
+        @Override
+        public <T> T[] getSpans(int start, int end, Class<T> type) {
+            return mText.getSpans(start, end, type);
+        }
+
+        @Override
+        public int getSpanStart(Object tag) {
+            return mText.getSpanStart(tag);
+        }
+
+        @Override
+        public int getSpanEnd(Object tag) {
+            return mText.getSpanEnd(tag);
+        }
+
+        @Override
+        public int getSpanFlags(Object tag) {
+            return mText.getSpanFlags(tag);
+        }
+
+        @Override
+        public int nextSpanTransition(int start, int limit, Class type) {
+            return mText.nextSpanTransition(start, limit, type);
+        }
+
+        @Override
+        public int length() {
+            return mText.length();
+        }
+
+        @Override
+        public char charAt(int index) {
+            return mText.charAt(index);
+        }
+
+        @Override
+        public CharSequence subSequence(int start, int end) {
+            return mText.subSequence(start, end);
+        }
+
+        @Override
+        public String toString() {
+            return mText.toString();
+        }
+    };
+}
diff --git a/core/tests/coretests/src/android/text/SpannedStringNoCopyTest.java b/core/tests/coretests/src/android/text/SpannedStringNoCopyTest.java
new file mode 100644
index 0000000..0680924
--- /dev/null
+++ b/core/tests/coretests/src/android/text/SpannedStringNoCopyTest.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+
+import android.annotation.NonNull;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.style.QuoteSpan;
+import android.text.style.UnderlineSpan;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SpannedStringNoCopyTest {
+    @Test
+    public void testCopyConstructor_copyNoCopySpans_SpannableStringInternalImpl() {
+        final SpannableString first = new SpannableString("t\nest data");
+        first.setSpan(new QuoteSpan(), 0, 2, Spanned.SPAN_PARAGRAPH);
+        first.setSpan(new NoCopySpan.Concrete(), 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        first.setSpan(new UnderlineSpan(), 0, first.length(), Spanned.SPAN_PRIORITY);
+
+        // By default, copy NoCopySpans
+        final SpannedString copied = new SpannedString(first);
+        final Object[] spans = copied.getSpans(0, copied.length(), Object.class);
+        assertNotNull(spans);
+        assertEquals(3, spans.length);
+    }
+
+    @Test
+    public void testCopyConstructor_doesNotCopyNoCopySpans_SpannableStringInternalImpl() {
+        final SpannableString first = new SpannableString("t\nest data");
+        first.setSpan(new QuoteSpan(), 0, 2, Spanned.SPAN_PARAGRAPH);
+        first.setSpan(new NoCopySpan.Concrete(), 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        first.setSpan(new UnderlineSpan(), 0, first.length(), Spanned.SPAN_PRIORITY);
+
+        // Do not copy NoCopySpan if specified so.
+        final SpannedString copied = new SpannedString(first, false /* copyNoCopySpan */);
+        final Object[] spans = copied.getSpans(0, copied.length(), Object.class);
+        assertNotNull(spans);
+        assertEquals(2, spans.length);
+
+        for (int i = 0; i < spans.length; i++) {
+            assertFalse(spans[i] instanceof NoCopySpan);
+        }
+    }
+
+    @Test
+    public void testCopyConstructor_copyNoCopySpans_OtherSpannedImpl() {
+        final SpannableString first = new SpannableString("t\nest data");
+        first.setSpan(new QuoteSpan(), 0, 2, Spanned.SPAN_PARAGRAPH);
+        first.setSpan(new NoCopySpan.Concrete(), 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        first.setSpan(new UnderlineSpan(), 0, first.length(), Spanned.SPAN_PRIORITY);
+
+        // By default, copy NoCopySpans
+        final SpannedString copied = new SpannedString(new CustomSpanned(first));
+        final Object[] spans = copied.getSpans(0, copied.length(), Object.class);
+        assertNotNull(spans);
+        assertEquals(3, spans.length);
+    }
+
+    @Test
+    public void testCopyConstructor_doesNotCopyNoCopySpans_OtherSpannedImpl() {
+        final SpannableString first = new SpannableString("t\nest data");
+        first.setSpan(new QuoteSpan(), 0, 2, Spanned.SPAN_PARAGRAPH);
+        first.setSpan(new NoCopySpan.Concrete(), 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        first.setSpan(new UnderlineSpan(), 0, first.length(), Spanned.SPAN_PRIORITY);
+
+        // Do not copy NoCopySpan if specified so.
+        final SpannedString copied = new SpannedString(
+                new CustomSpanned(first), false /* copyNoCopySpan */);
+        final Object[] spans = copied.getSpans(0, copied.length(), Object.class);
+        assertNotNull(spans);
+        assertEquals(2, spans.length);
+
+        for (int i = 0; i < spans.length; i++) {
+            assertFalse(spans[i] instanceof NoCopySpan);
+        }
+    }
+
+    // A custom implementation of Spanned
+    private static class CustomSpanned implements Spanned {
+        private final @NonNull Spanned mText;
+
+        CustomSpanned(@NonNull Spannable text) {
+            mText = text;
+        }
+
+        @Override
+        public <T> T[] getSpans(int start, int end, Class<T> type) {
+            return mText.getSpans(start, end, type);
+        }
+
+        @Override
+        public int getSpanStart(Object tag) {
+            return mText.getSpanStart(tag);
+        }
+
+        @Override
+        public int getSpanEnd(Object tag) {
+            return mText.getSpanEnd(tag);
+        }
+
+        @Override
+        public int getSpanFlags(Object tag) {
+            return mText.getSpanFlags(tag);
+        }
+
+        @Override
+        public int nextSpanTransition(int start, int limit, Class type) {
+            return mText.nextSpanTransition(start, limit, type);
+        }
+
+        @Override
+        public int length() {
+            return mText.length();
+        }
+
+        @Override
+        public char charAt(int index) {
+            return mText.charAt(index);
+        }
+
+        @Override
+        public CharSequence subSequence(int start, int end) {
+            return mText.subSequence(start, end);
+        }
+
+        @Override
+        public String toString() {
+            return mText.toString();
+        }
+    };
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 085e112..8f80527 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -176,33 +176,34 @@
     @Deprecated
     public WifiTracker(Context context, WifiListener wifiListener,
             boolean includeSaved, boolean includeScans) {
-        this(context, new WifiListenerExecutor(wifiListener),
+        this(context, wifiListener,
                 context.getSystemService(WifiManager.class),
                 context.getSystemService(ConnectivityManager.class),
                 context.getSystemService(NetworkScoreManager.class),
                 newIntentFilter());
     }
 
-    // TODO(Sghuman): Clean up includeSaved and includeScans from all constructors and linked
+    // TODO(sghuman): Clean up includeSaved and includeScans from all constructors and linked
     // calling apps once IC window is complete
     public WifiTracker(Context context, WifiListener wifiListener,
             @NonNull Lifecycle lifecycle, boolean includeSaved, boolean includeScans) {
-        this(context, new WifiListenerExecutor(wifiListener),
+        this(context, wifiListener,
                 context.getSystemService(WifiManager.class),
                 context.getSystemService(ConnectivityManager.class),
                 context.getSystemService(NetworkScoreManager.class),
                 newIntentFilter());
+
         lifecycle.addObserver(this);
     }
 
     @VisibleForTesting
-    WifiTracker(Context context, WifiListenerExecutor wifiListenerExecutor,
+    WifiTracker(Context context, WifiListener wifiListener,
             WifiManager wifiManager, ConnectivityManager connectivityManager,
             NetworkScoreManager networkScoreManager,
             IntentFilter filter) {
         mContext = context;
         mWifiManager = wifiManager;
-        mListener = wifiListenerExecutor;
+        mListener = new WifiListenerExecutor(wifiListener);
         mConnectivityManager = connectivityManager;
 
         // check if verbose logging developer option has been turned on or off
@@ -853,8 +854,7 @@
      *
      * <p>Also logs all callbacks invocations when verbose logging is enabled.
      */
-    @VisibleForTesting
-    public static class WifiListenerExecutor implements WifiListener {
+    @VisibleForTesting class WifiListenerExecutor implements WifiListener {
 
         private final WifiListener mDelegatee;
 
@@ -864,27 +864,29 @@
 
         @Override
         public void onWifiStateChanged(int state) {
-            if (isVerboseLoggingEnabled()) {
-                Log.i(TAG,
-                        String.format("Invoking onWifiStateChanged callback with state %d", state));
-            }
-            ThreadUtils.postOnMainThread(() -> mDelegatee.onWifiStateChanged(state));
+            runAndLog(() -> mDelegatee.onWifiStateChanged(state),
+                    String.format("Invoking onWifiStateChanged callback with state %d", state));
         }
 
         @Override
         public void onConnectedChanged() {
-            if (isVerboseLoggingEnabled()) {
-                Log.i(TAG, "Invoking onConnectedChanged callback");
-            }
-            ThreadUtils.postOnMainThread(() -> mDelegatee.onConnectedChanged());
+            runAndLog(mDelegatee::onConnectedChanged, "Invoking onConnectedChanged callback");
         }
 
         @Override
         public void onAccessPointsChanged() {
-            if (isVerboseLoggingEnabled()) {
-                Log.i(TAG, "Invoking onAccessPointsChanged callback");
-            }
-            ThreadUtils.postOnMainThread(() -> mDelegatee.onAccessPointsChanged());
+            runAndLog(mDelegatee::onAccessPointsChanged, "Invoking onAccessPointsChanged callback");
+        }
+
+        private void runAndLog(Runnable r, String verboseLog) {
+            ThreadUtils.postOnMainThread(() -> {
+                if (mRegistered) {
+                    if (isVerboseLoggingEnabled()) {
+                        Log.i(TAG, verboseLog);
+                    }
+                    r.run();
+                }
+            });
         }
     }
 
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 7fb4dc5..517db78 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -58,6 +58,8 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
+import com.android.settingslib.utils.ThreadUtils;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -135,7 +137,7 @@
     @Mock private RssiCurve mockBadgeCurve1;
     @Mock private RssiCurve mockBadgeCurve2;
     @Mock private WifiManager mockWifiManager;
-    @Mock private WifiTracker.WifiListenerExecutor mockWifiListenerExecutor;
+    @Mock private WifiTracker.WifiListener mockWifiListener;
 
     private final List<NetworkKey> mRequestedKeys = new ArrayList<>();
 
@@ -205,7 +207,7 @@
                       mAccessPointsChangedLatch.countDown();
                     }
                     return null;
-                }).when(mockWifiListenerExecutor).onAccessPointsChanged();
+                }).when(mockWifiListener).onAccessPointsChanged();
 
         // Turn on Scoring UI features
         mOriginalScoringUiSettingValue = Settings.Global.getInt(
@@ -271,7 +273,7 @@
     private WifiTracker createMockedWifiTracker() {
         final WifiTracker wifiTracker = new WifiTracker(
                 mContext,
-                mockWifiListenerExecutor,
+                mockWifiListener,
                 mockWifiManager,
                 mockConnectivityManager,
                 mockNetworkScoreManager,
@@ -690,7 +692,7 @@
         verify(mockConnectivityManager).getNetworkInfo(any(Network.class));
 
         // mStaleAccessPoints is true
-        verify(mockWifiListenerExecutor, never()).onAccessPointsChanged();
+        verify(mockWifiListener, never()).onAccessPointsChanged();
         assertThat(tracker.getAccessPoints().size()).isEqualTo(2);
         assertThat(tracker.getAccessPoints().get(0).isActive()).isTrue();
     }
@@ -719,7 +721,7 @@
         verify(mockConnectivityManager).getNetworkInfo(any(Network.class));
 
         // mStaleAccessPoints is true
-        verify(mockWifiListenerExecutor, never()).onAccessPointsChanged();
+        verify(mockWifiListener, never()).onAccessPointsChanged();
 
         assertThat(tracker.getAccessPoints()).hasSize(1);
         assertThat(tracker.getAccessPoints().get(0).isActive()).isTrue();
@@ -762,6 +764,41 @@
     }
 
     @Test
+    public void stopTrackingShouldPreventCallbacksFromOngoingWork() throws Exception {
+        WifiTracker tracker = createMockedWifiTracker();
+        startTracking(tracker);
+
+        final CountDownLatch ready = new CountDownLatch(1);
+        final CountDownLatch latch = new CountDownLatch(1);
+        final CountDownLatch lock = new CountDownLatch(1);
+        tracker.mWorkHandler.post(() -> {
+            try {
+                ready.countDown();
+                lock.await();
+
+                tracker.mReceiver.onReceive(
+                        mContext, new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION));
+
+                latch.countDown();
+            } catch (InterruptedException e) {
+                fail("Interrupted Exception while awaiting lock release: " + e);
+            }
+        });
+
+        ready.await(); // Make sure we have entered the first message handler
+        tracker.onStop();
+        lock.countDown();
+        assertTrue("Latch timed out", latch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
+
+        // Wait for main thread
+        final CountDownLatch latch2 = new CountDownLatch(1);
+        ThreadUtils.postOnMainThread(latch2::countDown);
+        latch2.await();
+
+        verify(mockWifiListener, never()).onWifiStateChanged(anyInt());
+    }
+
+    @Test
     public void stopTrackingShouldSetStaleBitWhichPreventsCallbacksUntilNextScanResult()
             throws Exception {
         WifiTracker tracker = createMockedWifiTracker();
@@ -778,7 +815,7 @@
                 mContext, new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION));
 
 
-        verify(mockWifiListenerExecutor, never()).onAccessPointsChanged();
+        verify(mockWifiListener, never()).onAccessPointsChanged();
 
         sendScanResults(tracker); // verifies onAccessPointsChanged is invoked
     }
@@ -795,7 +832,7 @@
         tracker.mReceiver.onReceive(
                 mContext, new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION));
 
-        verify(mockWifiListenerExecutor, never()).onAccessPointsChanged();
+        verify(mockWifiListener, never()).onAccessPointsChanged();
 
         sendScanResults(tracker); // verifies onAccessPointsChanged is invoked
     }
@@ -816,7 +853,7 @@
     @Test
     public void onConnectedChangedCallback_shouldNotBeInvokedWhenNoStateChange() throws Exception {
         WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
-        verify(mockWifiListenerExecutor, times(1)).onConnectedChanged();
+        verify(mockWifiListener, times(1)).onConnectedChanged();
 
         NetworkInfo networkInfo = new NetworkInfo(
                 ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
@@ -826,13 +863,13 @@
         intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
         tracker.mReceiver.onReceive(mContext, intent);
 
-        verify(mockWifiListenerExecutor, times(1)).onConnectedChanged();
+        verify(mockWifiListener, times(1)).onConnectedChanged();
     }
 
     @Test
     public void onConnectedChangedCallback_shouldBeInvokedWhenStateChanges() throws Exception {
         WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
-        verify(mockWifiListenerExecutor, times(1)).onConnectedChanged();
+        verify(mockWifiListener, times(1)).onConnectedChanged();
 
         NetworkInfo networkInfo = new NetworkInfo(
                 ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
@@ -844,7 +881,7 @@
         tracker.mReceiver.onReceive(mContext, intent);
 
         assertThat(tracker.isConnected()).isFalse();
-        verify(mockWifiListenerExecutor, times(2)).onConnectedChanged();
+        verify(mockWifiListener, times(2)).onConnectedChanged();
     }
 
     @Test
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index cb5763f..7de54db 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2774,9 +2774,7 @@
         }
 
         private void notifyForSettingsChange(int key, String name) {
-            final int userId = isGlobalSettingsKey(key)
-                    ? UserHandle.USER_ALL : getUserIdFromKey(key);
-
+            final int userId = getUserIdFromKey(key);
             Uri uri = getNotificationUriFor(key, name);
 
             mGenerationRegistry.incrementGeneration(key);
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index e0e666c..c5b3222 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1850,6 +1850,9 @@
     <!-- Label for area where tiles can be dragged in to [CHAR LIMIT=60] -->
     <string name="drag_to_remove_tiles">Drag here to remove</string>
 
+    <!-- Label to indicate to users that additional tiles cannot be removed. [CHAR LIMIT=60] -->
+    <string name="drag_to_remove_disabled">You need at least 6 tiles</string>
+
     <!-- Button to edit the tile ordering of quick settings [CHAR LIMIT=60] -->
     <string name="qs_edit">Edit</string>
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index bdc5e7d..3ba5fe6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -42,19 +42,19 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.systemui.R;
-import com.android.systemui.qs.tileimpl.QSIconViewImpl;
+import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.qs.customize.TileAdapter.Holder;
 import com.android.systemui.qs.customize.TileQueryHelper.TileInfo;
 import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener;
 import com.android.systemui.qs.external.CustomTile;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.tileimpl.QSIconViewImpl;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 
 import java.util.ArrayList;
 import java.util.List;
 
 public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileStateListener {
-
+    private static final int MIN_NUM_TILES = 6;
     private static final long DRAG_LENGTH = 100;
     private static final float DRAG_SCALE = 1.2f;
     public static final long MOVE_DURATION = 150;
@@ -219,9 +219,15 @@
             return;
         }
         if (holder.getItemViewType() == TYPE_EDIT) {
-            ((TextView) holder.itemView.findViewById(android.R.id.title)).setText(
-                    mCurrentDrag != null ? R.string.drag_to_remove_tiles
-                    : R.string.drag_to_add_tiles);
+            final int titleResId;
+            if (mCurrentDrag == null) {
+                titleResId = R.string.drag_to_add_tiles;
+            } else if (!canRemoveTiles() && mCurrentDrag.getAdapterPosition() < mEditIndex) {
+                titleResId = R.string.drag_to_remove_disabled;
+            } else {
+                titleResId = R.string.drag_to_remove_tiles;
+            }
+            ((TextView) holder.itemView.findViewById(android.R.id.title)).setText(titleResId);
             return;
         }
         if (holder.getItemViewType() == TYPE_ACCESSIBLE_DROP) {
@@ -286,7 +292,7 @@
                         if (mAccessibilityMoving) {
                             selectPosition(position, v);
                         } else {
-                            if (position < mEditIndex) {
+                            if (position < mEditIndex && canRemoveTiles()) {
                                 showAccessibilityDialog(position, v);
                             } else {
                                 startAccessibleDrag(position);
@@ -297,6 +303,10 @@
             }
         }
     }
+    
+    private boolean canRemoveTiles() {
+        return mCurrentSpecs.size() > MIN_NUM_TILES;
+    }
 
     private void selectPosition(int position, View v) {
         // Remove the placeholder.
@@ -507,7 +517,7 @@
                 break;
             }
         }
-    };
+    }
 
     private final ItemTouchHelper.Callback mCallbacks = new ItemTouchHelper.Callback() {
 
@@ -551,6 +561,9 @@
         @Override
         public boolean canDropOver(RecyclerView recyclerView, ViewHolder current,
                 ViewHolder target) {
+            if (!canRemoveTiles() && current.getAdapterPosition() < mEditIndex) {
+                return target.getAdapterPosition() < mEditIndex;
+            }
             return target.getAdapterPosition() <= mEditIndex + 1;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index ebd2261..775faee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -531,6 +531,14 @@
         return null;
     }
 
+    public boolean shouldHide(String key) {
+        if (mRankingMap != null) {
+            getRanking(key, mTmpRanking);
+            return mTmpRanking.isSuspended();
+        }
+        return false;
+    }
+
     private void updateRankingAndSort(RankingMap ranking) {
         if (ranking != null) {
             mRankingMap = ranking;
@@ -620,6 +628,10 @@
             return true;
         }
 
+        if (shouldHide(sbn.getKey())) {
+            return true;
+        }
+
         if (!StatusBar.ENABLE_CHILD_NOTIFICATIONS
                 && mGroupManager.isChildInGroupWithSummary(sbn)) {
             return true;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java
index b1e1c02..2000bff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java
@@ -60,6 +60,7 @@
 
     private static final int UID_NORMAL = 123;
     private static final int UID_ALLOW_DURING_SETUP = 456;
+    private static final String TEST_HIDDEN_NOTIFICATION_KEY = "testHiddenNotificationKey";
 
     private final StatusBarNotification mMockStatusBarNotification =
             mock(StatusBarNotification.class);
@@ -247,6 +248,22 @@
         assertFalse(mNotificationData.shouldFilterOut(mRow.getEntry().notification));
     }
 
+    @Test
+    public void testShouldFilterHiddenNotifications() {
+        // setup
+        when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(false);
+        when(mFsc.isSystemAlertNotification(any())).thenReturn(false);
+
+        // test should filter out hidden notifications:
+        // hidden
+        when(mMockStatusBarNotification.getKey()).thenReturn(TEST_HIDDEN_NOTIFICATION_KEY);
+        assertTrue(mNotificationData.shouldFilterOut(mMockStatusBarNotification));
+
+        // not hidden
+        when(mMockStatusBarNotification.getKey()).thenReturn("not hidden");
+        assertFalse(mNotificationData.shouldFilterOut(mMockStatusBarNotification));
+    }
+
     private void initStatusBarNotification(boolean allowDuringSetup) {
         Bundle bundle = new Bundle();
         bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup);
@@ -269,6 +286,21 @@
         @Override
         protected boolean getRanking(String key, NotificationListenerService.Ranking outRanking) {
             super.getRanking(key, outRanking);
+            if (key.equals(TEST_HIDDEN_NOTIFICATION_KEY)) {
+                outRanking.populate(key, outRanking.getRank(),
+                        outRanking.matchesInterruptionFilter(),
+                        outRanking.getVisibilityOverride(), outRanking.getSuppressedVisualEffects(),
+                        outRanking.getImportance(), outRanking.getImportanceExplanation(),
+                        outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
+                        outRanking.canShowBadge(), outRanking.getUserSentiment(), true);
+            } else {
+                outRanking.populate(key, outRanking.getRank(),
+                        outRanking.matchesInterruptionFilter(),
+                        outRanking.getVisibilityOverride(), outRanking.getSuppressedVisualEffects(),
+                        outRanking.getImportance(), outRanking.getImportanceExplanation(),
+                        outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
+                        outRanking.canShowBadge(), outRanking.getUserSentiment(), false);
+            }
             return true;
         }
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java
index 7e5db34..3703d6a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java
@@ -140,7 +140,7 @@
                     0,
                     NotificationManager.IMPORTANCE_DEFAULT,
                     null, null,
-                    null, null, null, true, sentiment);
+                    null, null, null, true, sentiment, false);
             return true;
         }).when(mRankingMap).getRanking(eq(key), any(NotificationListenerService.Ranking.class));
     }
diff --git a/services/core/java/com/android/server/fingerprint/ClientMonitor.java b/services/core/java/com/android/server/fingerprint/ClientMonitor.java
index 3eae157..4100a9a 100644
--- a/services/core/java/com/android/server/fingerprint/ClientMonitor.java
+++ b/services/core/java/com/android/server/fingerprint/ClientMonitor.java
@@ -21,6 +21,7 @@
 import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
+import android.media.AudioAttributes;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.VibrationEffect;
@@ -39,6 +40,11 @@
     protected static final int ERROR_ESRCH = 3; // Likely fingerprint HAL is dead. See errno.h.
     protected static final boolean DEBUG = FingerprintService.DEBUG;
     private static final long[] DEFAULT_SUCCESS_VIBRATION_PATTERN = new long[] {0, 30};
+    private static final AudioAttributes FINGERPRINT_SONFICATION_ATTRIBUTES =
+            new AudioAttributes.Builder()
+                    .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+                    .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+                    .build();
     private final Context mContext;
     private final long mHalDeviceId;
     private final int mTargetUserId;
@@ -223,14 +229,14 @@
     public final void vibrateSuccess() {
         Vibrator vibrator = mContext.getSystemService(Vibrator.class);
         if (vibrator != null) {
-            vibrator.vibrate(mSuccessVibrationEffect);
+            vibrator.vibrate(mSuccessVibrationEffect, FINGERPRINT_SONFICATION_ATTRIBUTES);
         }
     }
 
     public final void vibrateError() {
         Vibrator vibrator = mContext.getSystemService(Vibrator.class);
         if (vibrator != null) {
-            vibrator.vibrate(mErrorVibrationEffect);
+            vibrator.vibrate(mErrorVibrationEffect, FINGERPRINT_SONFICATION_ATTRIBUTES);
         }
     }
 
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 729ac0c..e02feec 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1721,7 +1721,9 @@
         if (mItarSpeedLimitExceeded) {
             Log.i(TAG, "Hal reported a speed in excess of ITAR limit." +
                     "  GPS/GNSS Navigation output blocked.");
-            mGnssMetrics.logReceivedLocationStatus(false);
+            if (mStarted) {
+                mGnssMetrics.logReceivedLocationStatus(false);
+            }
             return;  // No output of location allowed
         }
 
@@ -1738,14 +1740,16 @@
             Log.e(TAG, "RemoteException calling reportLocation");
         }
 
-        mGnssMetrics.logReceivedLocationStatus(hasLatLong);
-        if (hasLatLong) {
-            if (location.hasAccuracy()) {
-                mGnssMetrics.logPositionAccuracyMeters(location.getAccuracy());
-            }
-            if (mTimeToFirstFix > 0) {
-                int timeBetweenFixes = (int) (SystemClock.elapsedRealtime() - mLastFixTime);
-                mGnssMetrics.logMissedReports(mFixInterval, timeBetweenFixes);
+        if (mStarted) {
+            mGnssMetrics.logReceivedLocationStatus(hasLatLong);
+            if (hasLatLong) {
+                if (location.hasAccuracy()) {
+                    mGnssMetrics.logPositionAccuracyMeters(location.getAccuracy());
+                }
+                if (mTimeToFirstFix > 0) {
+                    int timeBetweenFixes = (int) (SystemClock.elapsedRealtime() - mLastFixTime);
+                    mGnssMetrics.logMissedReports(mFixInterval, timeBetweenFixes);
+                }
             }
         }
 
@@ -1754,7 +1758,9 @@
         if (mTimeToFirstFix == 0 && hasLatLong) {
             mTimeToFirstFix = (int) (mLastFixTime - mFixRequestTime);
             if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
-            mGnssMetrics.logTimeToFirstFixMilliSecs(mTimeToFirstFix);
+            if (mStarted) {
+                mGnssMetrics.logTimeToFirstFixMilliSecs(mTimeToFirstFix);
+            }
 
             // notify status listeners
             mListenerHelper.onFirstFix(mTimeToFirstFix);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index cd19eb8..27eeb93 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -959,6 +959,8 @@
             boolean queryRemove = false;
             boolean packageChanged = false;
             boolean cancelNotifications = true;
+            boolean hideNotifications = false;
+            boolean unhideNotifications = false;
             int reason = REASON_PACKAGE_CHANGED;
 
             if (action.equals(Intent.ACTION_PACKAGE_ADDED)
@@ -967,7 +969,8 @@
                     || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
                     || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
                     || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
-                    || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
+                    || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)
+                    || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
                 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
                         UserHandle.USER_ALL);
                 String pkgList[] = null;
@@ -980,7 +983,12 @@
                     uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
                 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
-                    reason = REASON_PACKAGE_SUSPENDED;
+                    cancelNotifications = false;
+                    hideNotifications = true;
+                } else if (action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
+                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                    cancelNotifications = false;
+                    unhideNotifications = true;
                 } else if (queryRestart) {
                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
                     uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
@@ -1022,9 +1030,15 @@
                         if (cancelNotifications) {
                             cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
                                     !queryRestart, changeUserId, reason, null);
+                        } else if (hideNotifications) {
+                            hideNotificationsForPackages(pkgList);
+                        } else if (unhideNotifications) {
+                            unhideNotificationsForPackages(pkgList);
                         }
+
                     }
                 }
+
                 mListeners.onPackagesChanged(removingPackage, pkgList, uidList);
                 mAssistants.onPackagesChanged(removingPackage, pkgList, uidList);
                 mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList);
@@ -1479,6 +1493,7 @@
 
         IntentFilter suspendedPkgFilter = new IntentFilter();
         suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
+        suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
                 suspendedPkgFilter, null, null);
 
@@ -2486,6 +2501,7 @@
             try {
                 synchronized (mNotificationLock) {
                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
+
                     if (keys != null) {
                         final int N = keys.length;
                         for (int i = 0; i < N; i++) {
@@ -4271,6 +4287,14 @@
         }
     }
 
+    @GuardedBy("mNotificationLock")
+    private boolean isPackageSuspendedLocked(NotificationRecord r) {
+        final String pkg = r.sbn.getPackageName();
+        final int callingUid = r.sbn.getUid();
+
+        return isPackageSuspendedForUser(pkg, callingUid);
+    }
+
     protected class PostNotificationRunnable implements Runnable {
         private final String key;
 
@@ -4295,6 +4319,8 @@
                         Slog.i(TAG, "Cannot find enqueued record for key: " + key);
                         return;
                     }
+
+                    r.setHidden(isPackageSuspendedLocked(r));
                     NotificationRecord old = mNotificationsByKey.get(key);
                     final StatusBarNotification n = r.sbn;
                     final Notification notification = n.getNotification();
@@ -4347,7 +4373,7 @@
                     } else {
                         Slog.e(TAG, "Not posting notification without small icon: " + notification);
                         if (old != null && !old.isCanceled) {
-                            mListeners.notifyRemovedLocked(n,
+                            mListeners.notifyRemovedLocked(r,
                                     NotificationListenerService.REASON_ERROR, null);
                             mHandler.post(new Runnable() {
                                 @Override
@@ -4363,7 +4389,9 @@
                                 + n.getPackageName());
                     }
 
-                    buzzBeepBlinkLocked(r);
+                    if (!r.isHidden()) {
+                        buzzBeepBlinkLocked(r);
+                    }
                     maybeRecordInterruptionLocked(r);
                 } finally {
                     int N = mEnqueuedNotifications.size();
@@ -5022,7 +5050,7 @@
 
     private void handleSendRankingUpdate() {
         synchronized (mNotificationLock) {
-            mListeners.notifyRankingUpdateLocked();
+            mListeners.notifyRankingUpdateLocked(null);
         }
     }
 
@@ -5207,7 +5235,7 @@
                 if (reason != REASON_SNOOZED) {
                     r.isCanceled = true;
                 }
-                mListeners.notifyRemovedLocked(r.sbn, reason, r.getStats());
+                mListeners.notifyRemovedLocked(r, reason, r.getStats());
                 mHandler.post(new Runnable() {
                     @Override
                     public void run() {
@@ -5316,6 +5344,7 @@
             final String pkg, final String tag, final int id,
             final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
             final int userId, final int reason, final ManagedServiceInfo listener) {
+
         // In enqueueNotificationInternal notifications are added by scheduling the
         // work on the worker handler. Hence, we also schedule the cancel on this
         // handler to avoid a scenario where an add notification call followed by a
@@ -5707,6 +5736,42 @@
         return -1;
     }
 
+    @VisibleForTesting
+    protected void hideNotificationsForPackages(String[] pkgs) {
+        synchronized (mNotificationLock) {
+            List<String> pkgList = Arrays.asList(pkgs);
+            List<NotificationRecord> changedNotifications = new ArrayList<>();
+            int numNotifications = mNotificationList.size();
+            for (int i = 0; i < numNotifications; i++) {
+                NotificationRecord rec = mNotificationList.get(i);
+                if (pkgList.contains(rec.sbn.getPackageName())) {
+                    rec.setHidden(true);
+                    changedNotifications.add(rec);
+                }
+            }
+
+            mListeners.notifyHiddenLocked(changedNotifications);
+        }
+    }
+
+    @VisibleForTesting
+    protected void unhideNotificationsForPackages(String[] pkgs) {
+        synchronized (mNotificationLock) {
+            List<String> pkgList = Arrays.asList(pkgs);
+            List<NotificationRecord> changedNotifications = new ArrayList<>();
+            int numNotifications = mNotificationList.size();
+            for (int i = 0; i < numNotifications; i++) {
+                NotificationRecord rec = mNotificationList.get(i);
+                if (pkgList.contains(rec.sbn.getPackageName())) {
+                    rec.setHidden(false);
+                    changedNotifications.add(rec);
+                }
+            }
+
+            mListeners.notifyUnhiddenLocked(changedNotifications);
+        }
+    }
+
     private void updateNotificationPulse() {
         synchronized (mNotificationLock) {
             updateLightsLocked();
@@ -5826,6 +5891,7 @@
         Bundle snoozeCriteria = new Bundle();
         Bundle showBadge = new Bundle();
         Bundle userSentiment = new Bundle();
+        Bundle hidden = new Bundle();
         for (int i = 0; i < N; i++) {
             NotificationRecord record = mNotificationList.get(i);
             if (!isVisibleToListener(record.sbn, info)) {
@@ -5852,6 +5918,7 @@
             snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
             showBadge.putBoolean(key, record.canShowBadge());
             userSentiment.putInt(key, record.getUserSentiment());
+            hidden.putBoolean(key, record.isHidden());
         }
         final int M = keys.size();
         String[] keysAr = keys.toArray(new String[M]);
@@ -5862,7 +5929,7 @@
         }
         return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
                 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
-                channels, overridePeople, snoozeCriteria, showBadge, userSentiment);
+                channels, overridePeople, snoozeCriteria, showBadge, userSentiment, hidden);
     }
 
     boolean hasCompanionDevice(ManagedServiceInfo info) {
@@ -6151,6 +6218,16 @@
          */
         @GuardedBy("mNotificationLock")
         public void notifyPostedLocked(NotificationRecord r, StatusBarNotification oldSbn) {
+            notifyPostedLocked(r, oldSbn, true);
+        }
+
+        /**
+         * @param notifyAllListeners notifies all listeners if true, else only notifies listeners
+         *                           targetting <= O_MR1
+         */
+        @GuardedBy("mNotificationLock")
+        private void notifyPostedLocked(NotificationRecord r, StatusBarNotification oldSbn,
+                boolean notifyAllListeners) {
             // Lazily initialized snapshots of the notification.
             StatusBarNotification sbn = r.sbn;
             TrimCache trimCache = new TrimCache(sbn);
@@ -6164,6 +6241,21 @@
                 if (!oldSbnVisible && !sbnVisible) {
                     continue;
                 }
+
+                // If the notification is hidden, don't notifyPosted listeners targeting < P.
+                // Instead, those listeners will receive notifyPosted when the notification is
+                // unhidden.
+                if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) {
+                    continue;
+                }
+
+                // If we shouldn't notify all listeners, this means the hidden state of
+                // a notification was changed.  Don't notifyPosted listeners targeting >= P.
+                // Instead, those listeners will receive notifyRankingUpdate.
+                if (!notifyAllListeners && info.targetSdkVersion >= Build.VERSION_CODES.P) {
+                    continue;
+                }
+
                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
 
                 // This notification became invisible -> remove the old one.
@@ -6218,8 +6310,9 @@
          * asynchronously notify all listeners about a removed notification
          */
         @GuardedBy("mNotificationLock")
-        public void notifyRemovedLocked(StatusBarNotification sbn, int reason,
+        public void notifyRemovedLocked(NotificationRecord r, int reason,
                 NotificationStats notificationStats) {
+            final StatusBarNotification sbn = r.sbn;
             // make a copy in case changes are made to the underlying Notification object
             // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
             // notification
@@ -6228,6 +6321,21 @@
                 if (!isVisibleToListener(sbn, info)) {
                     continue;
                 }
+
+                // don't notifyRemoved for listeners targeting < P
+                // if not for reason package suspended
+                if (r.isHidden() && reason != REASON_PACKAGE_SUSPENDED
+                        && info.targetSdkVersion < Build.VERSION_CODES.P) {
+                    continue;
+                }
+
+                // don't notifyRemoved for listeners targeting >= P
+                // if the reason is package suspended
+                if (reason == REASON_PACKAGE_SUSPENDED
+                        && info.targetSdkVersion >= Build.VERSION_CODES.P) {
+                    continue;
+                }
+
                 // Only assistants can get stats
                 final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service)
                         ? notificationStats : null;
@@ -6242,21 +6350,44 @@
         }
 
         /**
-         * asynchronously notify all listeners about a reordering of notifications
+         * Asynchronously notify all listeners about a reordering of notifications
+         * unless changedHiddenNotifications is populated.
+         * If changedHiddenNotifications is populated, there was a change in the hidden state
+         * of the notifications.  In this case, we only send updates to listeners that
+         * target >= P.
          */
         @GuardedBy("mNotificationLock")
-        public void notifyRankingUpdateLocked() {
+        public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) {
+            boolean isHiddenRankingUpdate = changedHiddenNotifications != null
+                    && changedHiddenNotifications.size() > 0;
+
             for (final ManagedServiceInfo serviceInfo : getServices()) {
                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
                     continue;
                 }
-                final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
-                mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        notifyRankingUpdate(serviceInfo, update);
+
+                boolean notifyThisListener = false;
+                if (isHiddenRankingUpdate && serviceInfo.targetSdkVersion >=
+                        Build.VERSION_CODES.P) {
+                    for (NotificationRecord rec : changedHiddenNotifications) {
+                        if (isVisibleToListener(rec.sbn, serviceInfo)) {
+                            notifyThisListener = true;
+                            break;
+                        }
                     }
-                });
+                }
+
+                if (notifyThisListener || !isHiddenRankingUpdate) {
+                    final NotificationRankingUpdate update = makeRankingUpdateLocked(
+                            serviceInfo);
+
+                    mHandler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            notifyRankingUpdate(serviceInfo, update);
+                        }
+                    });
+                }
             }
         }
 
@@ -6275,6 +6406,52 @@
             }
         }
 
+        /**
+         * asynchronously notify relevant listeners their notification is hidden
+         * NotificationListenerServices that target P+:
+         *      NotificationListenerService#notifyRankingUpdateLocked()
+         * NotificationListenerServices that target <= P:
+         *      NotificationListenerService#notifyRemovedLocked() with REASON_PACKAGE_SUSPENDED.
+         */
+        @GuardedBy("mNotificationLock")
+        public void notifyHiddenLocked(List<NotificationRecord> changedNotifications) {
+            if (changedNotifications == null || changedNotifications.size() == 0) {
+                return;
+            }
+
+            notifyRankingUpdateLocked(changedNotifications);
+
+            // for listeners that target < P, notifyRemoveLocked
+            int numChangedNotifications = changedNotifications.size();
+            for (int i = 0; i < numChangedNotifications; i++) {
+                NotificationRecord rec = changedNotifications.get(i);
+                mListeners.notifyRemovedLocked(rec, REASON_PACKAGE_SUSPENDED, rec.getStats());
+            }
+        }
+
+        /**
+         * asynchronously notify relevant listeners their notification is unhidden
+         * NotificationListenerServices that target P+:
+         *      NotificationListenerService#notifyRankingUpdateLocked()
+         * NotificationListenerServices that target <= P:
+         *      NotificationListeners#notifyPostedLocked()
+         */
+        @GuardedBy("mNotificationLock")
+        public void notifyUnhiddenLocked(List<NotificationRecord> changedNotifications) {
+            if (changedNotifications == null || changedNotifications.size() == 0) {
+                return;
+            }
+
+            notifyRankingUpdateLocked(changedNotifications);
+
+            // for listeners that target < P, notifyPostedLocked
+            int numChangedNotifications = changedNotifications.size();
+            for (int i = 0; i < numChangedNotifications; i++) {
+                NotificationRecord rec = changedNotifications.get(i);
+                mListeners.notifyPostedLocked(rec, rec.sbn, false);
+            }
+        }
+
         public void notifyInterruptionFilterChanged(final int interruptionFilter) {
             for (final ManagedServiceInfo serviceInfo : getServices()) {
                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
@@ -6503,6 +6680,22 @@
         }
     }
 
+    @VisibleForTesting
+    protected void simulatePackageSuspendBroadcast(boolean suspend, String pkg) {
+        // only use for testing: mimic receive broadcast that package is (un)suspended
+        // but does not actually (un)suspend the package
+        final Bundle extras = new Bundle();
+        extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
+                new String[]{pkg});
+
+        final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED
+            : Intent.ACTION_PACKAGES_UNSUSPENDED;
+        final Intent intent = new Intent(action);
+        intent.putExtras(extras);
+
+        mPackageIntentReceiver.onReceive(getContext(), intent);
+    }
+
     /**
      * Wrapper for a StatusBarNotification object that allows transfer across a oneway
      * binder without sending large amounts of data over a oneway transaction.
@@ -6531,7 +6724,9 @@
                 + "allow_assistant COMPONENT\n"
                 + "remove_assistant COMPONENT\n"
                 + "allow_dnd PACKAGE\n"
-                + "disallow_dnd PACKAGE";
+                + "disallow_dnd PACKAGE\n"
+                + "suspend_package PACKAGE\n"
+                + "unsuspend_package PACKAGE";
 
         @Override
         public int onCommand(String cmd) {
@@ -6600,7 +6795,16 @@
                         getBinderService().setNotificationAssistantAccessGranted(cn, false);
                     }
                     break;
-
+                    case "suspend_package": {
+                        // only use for testing
+                        simulatePackageSuspendBroadcast(true, getNextArgRequired());
+                    }
+                    break;
+                    case "unsuspend_package": {
+                        // only use for testing
+                        simulatePackageSuspendBroadcast(false, getNextArgRequired());
+                    }
+                    break;
                     default:
                         return handleDefaultCommands(cmd);
                 }
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index f1908bf..c887085 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -103,6 +103,9 @@
     // is this notification currently being intercepted by Zen Mode?
     private boolean mIntercept;
 
+    // is this notification hidden since the app pkg is suspended?
+    private boolean mHidden;
+
     // The timestamp used for ranking.
     private long mRankingTimeMs;
 
@@ -353,6 +356,7 @@
         mPackagePriority = previous.mPackagePriority;
         mPackageVisibility = previous.mPackageVisibility;
         mIntercept = previous.mIntercept;
+        mHidden = previous.mHidden;
         mRankingTimeMs = calculateRankingTimeMs(previous.getRankingTimeMs());
         mCreationTimeMs = previous.mCreationTimeMs;
         mVisibleSinceMs = previous.mVisibleSinceMs;
@@ -498,6 +502,7 @@
                 + NotificationListenerService.Ranking.importanceToString(mImportance));
         pw.println(prefix + "mImportanceExplanation=" + mImportanceExplanation);
         pw.println(prefix + "mIntercept=" + mIntercept);
+        pw.println(prefix + "mHidden==" + mHidden);
         pw.println(prefix + "mGlobalSortKey=" + mGlobalSortKey);
         pw.println(prefix + "mRankingTimeMs=" + mRankingTimeMs);
         pw.println(prefix + "mCreationTimeMs=" + mCreationTimeMs);
@@ -702,6 +707,15 @@
         return mIntercept;
     }
 
+    public void setHidden(boolean hidden) {
+        mHidden = hidden;
+    }
+
+    public boolean isHidden() {
+        return mHidden;
+    }
+
+
     public void setSuppressedVisualEffects(int effects) {
         mSuppressedVisualEffects = effects;
     }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 6cd60e6a..61b1eb4 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -999,7 +999,7 @@
             resolver.registerContentObserver(Settings.Global.getUriFor(
                     Settings.Global.POLICY_CONTROL), false, this,
                     UserHandle.USER_ALL);
-            resolver.registerContentObserver(Settings.Global.getUriFor(
+            resolver.registerContentObserver(Settings.Secure.getUriFor(
                     Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED), false, this,
                     UserHandle.USER_ALL);
             updateSettings();
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 410eddf..993f8af 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -512,7 +512,7 @@
             mDrawState = NO_SURFACE;
             return null;
         } catch (Exception e) {
-            Slog.e(TAG, "Exception creating surface", e);
+            Slog.e(TAG, "Exception creating surface (parent dead?)", e);
             mDrawState = NO_SURFACE;
             return null;
         }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index e8170ee..d2fb1ca 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -4738,7 +4738,11 @@
 
     public void testOverrideApnAPIsFailWithPO() throws Exception {
         setupProfileOwner();
-        ApnSetting apn = (new ApnSetting.Builder()).build();
+        ApnSetting apn = (new ApnSetting.Builder())
+            .setApnName("test")
+            .setEntryName("test")
+            .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT)
+            .build();
         assertExpectException(SecurityException.class, null, () ->
                 dpm.addOverrideApn(admin1, apn));
         assertExpectException(SecurityException.class, null, () ->
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
index f4313b8..181fceb 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
@@ -70,6 +70,7 @@
             assertEquals(getSnoozeCriteria(key, i), ranking.getSnoozeCriteria());
             assertEquals(getShowBadge(i), ranking.canShowBadge());
             assertEquals(getUserSentiment(i), ranking.getUserSentiment());
+            assertEquals(getHidden(i), ranking.isSuspended());
         }
     }
 
@@ -85,6 +86,7 @@
         Bundle showBadge = new Bundle();
         int[] importance = new int[mKeys.length];
         Bundle userSentiment = new Bundle();
+        Bundle mHidden = new Bundle();
 
         for (int i = 0; i < mKeys.length; i++) {
             String key = mKeys[i];
@@ -101,11 +103,12 @@
             snoozeCriteria.putParcelableArrayList(key, getSnoozeCriteria(key, i));
             showBadge.putBoolean(key, getShowBadge(i));
             userSentiment.putInt(key, getUserSentiment(i));
+            mHidden.putBoolean(key, getHidden(i));
         }
         NotificationRankingUpdate update = new NotificationRankingUpdate(mKeys,
                 interceptedKeys.toArray(new String[0]), visibilityOverrides,
                 suppressedVisualEffects, importance, explanation, overrideGroupKeys,
-                channels, overridePeople, snoozeCriteria, showBadge, userSentiment);
+                channels, overridePeople, snoozeCriteria, showBadge, userSentiment, mHidden);
         return update;
     }
 
@@ -153,6 +156,10 @@
         return USER_SENTIMENT_NEUTRAL;
     }
 
+    private boolean getHidden(int index) {
+        return index % 2 == 0;
+    }
+
     private ArrayList<String> getPeople(String key, int index) {
         ArrayList<String> people = new ArrayList<>();
         for (int i = 0; i < index; i++) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 9afaa24..b82becd 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -2739,4 +2739,44 @@
 
         assertFalse(mService.isVisuallyInterruptive(r1, r2));
     }
+
+    @Test
+    public void testHideAndUnhideNotificationsOnSuspendedPackageBroadcast() {
+        // post 2 notification from this package
+        final NotificationRecord notif1 = generateNotificationRecord(
+                mTestNotificationChannel, 1, null, true);
+        final NotificationRecord notif2 = generateNotificationRecord(
+                mTestNotificationChannel, 2, null, false);
+        mService.addNotification(notif1);
+        mService.addNotification(notif2);
+
+        // on broadcast, hide the 2 notifications
+        mService.simulatePackageSuspendBroadcast(true, PKG);
+        ArgumentCaptor<List> captorHide = ArgumentCaptor.forClass(List.class);
+        verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture());
+        assertEquals(2, captorHide.getValue().size());
+
+        // on broadcast, unhide the 2 notifications
+        mService.simulatePackageSuspendBroadcast(false, PKG);
+        ArgumentCaptor<List> captorUnhide = ArgumentCaptor.forClass(List.class);
+        verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture());
+        assertEquals(2, captorUnhide.getValue().size());
+    }
+
+    @Test
+    public void testNoNotificationsHiddenOnSuspendedPackageBroadcast() {
+        // post 2 notification from this package
+        final NotificationRecord notif1 = generateNotificationRecord(
+                mTestNotificationChannel, 1, null, true);
+        final NotificationRecord notif2 = generateNotificationRecord(
+                mTestNotificationChannel, 2, null, false);
+        mService.addNotification(notif1);
+        mService.addNotification(notif2);
+
+        // on broadcast, nothing is hidden since no notifications are of package "test_package"
+        mService.simulatePackageSuspendBroadcast(true, "test_package");
+        ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
+        verify(mListeners, times(1)).notifyHiddenLocked(captor.capture());
+        assertEquals(0, captor.getValue().size());
+    }
 }
diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java
index 992545d..7475c74 100644
--- a/telephony/java/android/telephony/CellIdentityTdscdma.java
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.text.TextUtils;
 
@@ -34,6 +35,10 @@
     private final int mCid;
     // 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown.
     private final int mCpid;
+    // long alpha Operator Name String or Enhanced Operator Name String
+    private final String mAlphaLong;
+    // short alpha Operator Name String or Enhanced Operator Name String
+    private final String mAlphaShort;
 
     /**
      * @hide
@@ -43,6 +48,8 @@
         mLac = Integer.MAX_VALUE;
         mCid = Integer.MAX_VALUE;
         mCpid = Integer.MAX_VALUE;
+        mAlphaLong = null;
+        mAlphaShort = null;
     }
 
     /**
@@ -55,7 +62,7 @@
      * @hide
      */
     public CellIdentityTdscdma(int mcc, int mnc, int lac, int cid, int cpid) {
-        this(String.valueOf(mcc), String.valueOf(mnc), lac, cid, cpid);
+        this(String.valueOf(mcc), String.valueOf(mnc), lac, cid, cpid, null, null);
     }
 
     /**
@@ -65,6 +72,7 @@
      * @param cid 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown
      * @param cpid 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown
      *
+     * FIXME: This is a temporary constructor to facilitate migration.
      * @hide
      */
     public CellIdentityTdscdma(String mcc, String mnc, int lac, int cid, int cpid) {
@@ -72,10 +80,34 @@
         mLac = lac;
         mCid = cid;
         mCpid = cpid;
+        mAlphaLong = null;
+        mAlphaShort = null;
+    }
+
+    /**
+     * @param mcc 3-digit Mobile Country Code in string format
+     * @param mnc 2 or 3-digit Mobile Network Code in string format
+     * @param lac 16-bit Location Area Code, 0..65535, INT_MAX if unknown
+     * @param cid 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown
+     * @param cpid 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown
+     * @param alphal long alpha Operator Name String or Enhanced Operator Name String
+     * @param alphas short alpha Operator Name String or Enhanced Operator Name String
+     *
+     * @hide
+     */
+    public CellIdentityTdscdma(String mcc, String mnc, int lac, int cid, int cpid,
+            String alphal, String alphas) {
+        super(TAG, TYPE_TDSCDMA, mcc, mnc);
+        mLac = lac;
+        mCid = cid;
+        mCpid = cpid;
+        mAlphaLong = alphal;
+        mAlphaShort = alphas;
     }
 
     private CellIdentityTdscdma(CellIdentityTdscdma cid) {
-        this(cid.mMccStr, cid.mMncStr, cid.mLac, cid.mCid, cid.mCpid);
+        this(cid.mMccStr, cid.mMncStr, cid.mLac, cid.mCid,
+                cid.mCpid, cid.mAlphaLong, cid.mAlphaShort);
     }
 
     CellIdentityTdscdma copy() {
@@ -119,9 +151,31 @@
         return mCpid;
     }
 
+    /**
+     * @return The long alpha tag associated with the current scan result (may be the operator
+     * name string or extended operator name string). May be null if unknown.
+     *
+     * @hide
+     */
+    @Nullable
+    public CharSequence getOperatorAlphaLong() {
+        return mAlphaLong;
+    }
+
+    /**
+     * @return The short alpha tag associated with the current scan result (may be the operator
+     * name string or extended operator name string).  May be null if unknown.
+     *
+     * @hide
+     */
+    @Nullable
+    public CharSequence getOperatorAlphaShort() {
+        return mAlphaShort;
+    }
+
     @Override
     public int hashCode() {
-        return Objects.hash(mMccStr, mMncStr, mLac, mCid, mCpid);
+        return Objects.hash(mMccStr, mMncStr, mLac, mCid, mCpid, mAlphaLong, mAlphaShort);
     }
 
     @Override
@@ -139,7 +193,9 @@
                 && TextUtils.equals(mMncStr, o.mMncStr)
                 && mLac == o.mLac
                 && mCid == o.mCid
-                && mCpid == o.mCpid;
+                && mCpid == o.mCpid
+                && mAlphaLong == o.mAlphaLong
+                && mAlphaShort == o.mAlphaShort;
     }
 
     @Override
@@ -150,6 +206,8 @@
         .append(" mLac=").append(mLac)
         .append(" mCid=").append(mCid)
         .append(" mCpid=").append(mCpid)
+        .append(" mAlphaLong=").append(mAlphaLong)
+        .append(" mAlphaShort=").append(mAlphaShort)
         .append("}").toString();
     }
 
@@ -161,6 +219,8 @@
         dest.writeInt(mLac);
         dest.writeInt(mCid);
         dest.writeInt(mCpid);
+        dest.writeString(mAlphaLong);
+        dest.writeString(mAlphaShort);
     }
 
     /** Construct from Parcel, type has already been processed */
@@ -169,6 +229,8 @@
         mLac = in.readInt();
         mCid = in.readInt();
         mCpid = in.readInt();
+        mAlphaLong = in.readString();
+        mAlphaShort = in.readString();
 
         if (DBG) log(toString());
     }
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 73a05af..145ed7e 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -17,10 +17,10 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.StringDef;
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.hardware.radio.V1_0.ApnTypes;
+import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.provider.Telephony;
@@ -28,17 +28,15 @@
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.Log;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.net.InetAddress;
-import java.net.MalformedURLException;
-import java.net.URL;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -46,25 +44,184 @@
  */
 public class ApnSetting implements Parcelable {
 
-    static final String LOG_TAG = "ApnSetting";
+    private static final String LOG_TAG = "ApnSetting";
     private static final boolean VDBG = false;
 
+    private static final Map<String, Integer> APN_TYPE_STRING_MAP;
+    private static final Map<Integer, String> APN_TYPE_INT_MAP;
+    private static final Map<String, Integer> PROTOCOL_STRING_MAP;
+    private static final Map<Integer, String> PROTOCOL_INT_MAP;
+    private static final Map<String, Integer> MVNO_TYPE_STRING_MAP;
+    private static final Map<Integer, String> MVNO_TYPE_INT_MAP;
+    private static final int NOT_IN_MAP_INT = -1;
+    private static final int NO_PORT_SPECIFIED = -1;
+
+    /** All APN types except IA. */
+    private static final int TYPE_ALL_BUT_IA = ApnTypes.ALL & (~ApnTypes.IA);
+
+    /** APN type for default data traffic and HiPri traffic. */
+    public static final int TYPE_DEFAULT = ApnTypes.DEFAULT | ApnTypes.HIPRI;
+    /** APN type for MMS traffic. */
+    public static final int TYPE_MMS = ApnTypes.MMS;
+    /** APN type for SUPL assisted GPS. */
+    public static final int TYPE_SUPL = ApnTypes.SUPL;
+    /** APN type for DUN traffic. */
+    public static final int TYPE_DUN = ApnTypes.DUN;
+    /** APN type for HiPri traffic. */
+    public static final int TYPE_HIPRI = ApnTypes.HIPRI;
+    /** APN type for accessing the carrier's FOTA portal, used for over the air updates. */
+    public static final int TYPE_FOTA = ApnTypes.FOTA;
+    /** APN type for IMS. */
+    public static final int TYPE_IMS = ApnTypes.IMS;
+    /** APN type for CBS. */
+    public static final int TYPE_CBS = ApnTypes.CBS;
+    /** APN type for IA Initial Attach APN. */
+    public static final int TYPE_IA = ApnTypes.IA;
+    /**
+     * APN type for Emergency PDN. This is not an IA apn, but is used
+     * for access to carrier services in an emergency call situation.
+     */
+    public static final int TYPE_EMERGENCY = ApnTypes.EMERGENCY;
+
+    /** @hide */
+    @IntDef(flag = true, prefix = { "TYPE_" }, value = {
+        TYPE_DEFAULT,
+        TYPE_MMS,
+        TYPE_SUPL,
+        TYPE_DUN,
+        TYPE_HIPRI,
+        TYPE_FOTA,
+        TYPE_IMS,
+        TYPE_CBS,
+        TYPE_IA,
+        TYPE_EMERGENCY
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ApnType {}
+
+    // Possible values for authentication types.
+    /** No authentication type. */
+    public static final int AUTH_TYPE_NONE = 0;
+    /** Authentication type for PAP. */
+    public static final int AUTH_TYPE_PAP = 1;
+    /** Authentication type for CHAP. */
+    public static final int AUTH_TYPE_CHAP = 2;
+    /** Authentication type for PAP or CHAP. */
+    public static final int AUTH_TYPE_PAP_OR_CHAP = 3;
+
+    /** @hide */
+    @IntDef(prefix = { "AUTH_TYPE_" }, value = {
+        AUTH_TYPE_NONE,
+        AUTH_TYPE_PAP,
+        AUTH_TYPE_CHAP,
+        AUTH_TYPE_PAP_OR_CHAP,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AuthType {}
+
+    // Possible values for protocol.
+    /** Protocol type for IP. */
+    public static final int PROTOCOL_IP = 0;
+    /** Protocol type for IPV6. */
+    public static final int PROTOCOL_IPV6 = 1;
+    /** Protocol type for IPV4V6. */
+    public static final int PROTOCOL_IPV4V6 = 2;
+    /** Protocol type for PPP. */
+    public static final int PROTOCOL_PPP = 3;
+
+    /** @hide */
+    @IntDef(prefix = { "PROTOCOL_" }, value = {
+        PROTOCOL_IP,
+        PROTOCOL_IPV6,
+        PROTOCOL_IPV4V6,
+        PROTOCOL_PPP,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ProtocolType {}
+
+    // Possible values for MVNO type.
+    /** MVNO type for service provider name. */
+    public static final int MVNO_TYPE_SPN = 0;
+    /** MVNO type for IMSI. */
+    public static final int MVNO_TYPE_IMSI = 1;
+    /** MVNO type for group identifier level 1. */
+    public static final int MVNO_TYPE_GID = 2;
+    /** MVNO type for ICCID. */
+    public static final int MVNO_TYPE_ICCID = 3;
+
+    /** @hide */
+    @IntDef(prefix = { "MVNO_TYPE_" }, value = {
+        MVNO_TYPE_SPN,
+        MVNO_TYPE_IMSI,
+        MVNO_TYPE_GID,
+        MVNO_TYPE_ICCID,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface MvnoType {}
+
+    static {
+        APN_TYPE_STRING_MAP = new ArrayMap<String, Integer>();
+        APN_TYPE_STRING_MAP.put("*", TYPE_ALL_BUT_IA);
+        APN_TYPE_STRING_MAP.put("default", TYPE_DEFAULT);
+        APN_TYPE_STRING_MAP.put("mms", TYPE_MMS);
+        APN_TYPE_STRING_MAP.put("supl", TYPE_SUPL);
+        APN_TYPE_STRING_MAP.put("dun", TYPE_DUN);
+        APN_TYPE_STRING_MAP.put("hipri", TYPE_HIPRI);
+        APN_TYPE_STRING_MAP.put("fota", TYPE_FOTA);
+        APN_TYPE_STRING_MAP.put("ims", TYPE_IMS);
+        APN_TYPE_STRING_MAP.put("cbs", TYPE_CBS);
+        APN_TYPE_STRING_MAP.put("ia", TYPE_IA);
+        APN_TYPE_STRING_MAP.put("emergency", TYPE_EMERGENCY);
+        APN_TYPE_INT_MAP = new ArrayMap<Integer, String>();
+        APN_TYPE_INT_MAP.put(TYPE_DEFAULT, "default");
+        APN_TYPE_INT_MAP.put(TYPE_MMS, "mms");
+        APN_TYPE_INT_MAP.put(TYPE_SUPL, "supl");
+        APN_TYPE_INT_MAP.put(TYPE_DUN, "dun");
+        APN_TYPE_INT_MAP.put(TYPE_HIPRI, "hipri");
+        APN_TYPE_INT_MAP.put(TYPE_FOTA, "fota");
+        APN_TYPE_INT_MAP.put(TYPE_IMS, "ims");
+        APN_TYPE_INT_MAP.put(TYPE_CBS, "cbs");
+        APN_TYPE_INT_MAP.put(TYPE_IA, "ia");
+        APN_TYPE_INT_MAP.put(TYPE_EMERGENCY, "emergency");
+
+        PROTOCOL_STRING_MAP = new ArrayMap<String, Integer>();
+        PROTOCOL_STRING_MAP.put("IP", PROTOCOL_IP);
+        PROTOCOL_STRING_MAP.put("IPV6", PROTOCOL_IPV6);
+        PROTOCOL_STRING_MAP.put("IPV4V6", PROTOCOL_IPV4V6);
+        PROTOCOL_STRING_MAP.put("PPP", PROTOCOL_PPP);
+        PROTOCOL_INT_MAP = new ArrayMap<Integer, String>();
+        PROTOCOL_INT_MAP.put(PROTOCOL_IP, "IP");
+        PROTOCOL_INT_MAP.put(PROTOCOL_IPV6, "IPV6");
+        PROTOCOL_INT_MAP.put(PROTOCOL_IPV4V6, "IPV4V6");
+        PROTOCOL_INT_MAP.put(PROTOCOL_PPP, "PPP");
+
+        MVNO_TYPE_STRING_MAP = new ArrayMap<String, Integer>();
+        MVNO_TYPE_STRING_MAP.put("spn", MVNO_TYPE_SPN);
+        MVNO_TYPE_STRING_MAP.put("imsi", MVNO_TYPE_IMSI);
+        MVNO_TYPE_STRING_MAP.put("gid", MVNO_TYPE_GID);
+        MVNO_TYPE_STRING_MAP.put("iccid", MVNO_TYPE_ICCID);
+        MVNO_TYPE_INT_MAP = new ArrayMap<Integer, String>();
+        MVNO_TYPE_INT_MAP.put(MVNO_TYPE_SPN, "spn");
+        MVNO_TYPE_INT_MAP.put(MVNO_TYPE_IMSI, "imsi");
+        MVNO_TYPE_INT_MAP.put(MVNO_TYPE_GID, "gid");
+        MVNO_TYPE_INT_MAP.put(MVNO_TYPE_ICCID, "iccid");
+    }
+
     private final String mEntryName;
     private final String mApnName;
-    private final InetAddress mProxy;
-    private final int mPort;
-    private final URL mMmsc;
-    private final InetAddress mMmsProxy;
-    private final int mMmsPort;
+    private final InetAddress mProxyAddress;
+    private final int mProxyPort;
+    private final Uri mMmsc;
+    private final InetAddress mMmsProxyAddress;
+    private final int mMmsProxyPort;
     private final String mUser;
     private final String mPassword;
     private final int mAuthType;
-    private final List<String> mTypes;
-    private final int mTypesBitmap;
+    private final int mApnTypeBitmask;
     private final int mId;
     private final String mOperatorNumeric;
-    private final String mProtocol;
-    private final String mRoamingProtocol;
+    private final int mProtocol;
+    private final int mRoamingProtocol;
     private final int mMtu;
 
     private final boolean mCarrierEnabled;
@@ -78,22 +235,12 @@
     private final int mWaitTime;
     private final int mMaxConnsTime;
 
-    private final String mMvnoType;
+    private final int mMvnoType;
     private final String mMvnoMatchData;
 
     private boolean mPermanentFailed = false;
 
     /**
-     * Returns the types bitmap of the APN.
-     *
-     * @return types bitmap of the APN
-     * @hide
-     */
-    public int getTypesBitmap() {
-        return mTypesBitmap;
-    }
-
-    /**
      * Returns the MTU size of the mobile interface to which the APN connected.
      *
      * @return the MTU size of the APN
@@ -211,8 +358,8 @@
      *
      * @return proxy address.
      */
-    public InetAddress getProxy() {
-        return mProxy;
+    public InetAddress getProxyAddress() {
+        return mProxyAddress;
     }
 
     /**
@@ -220,15 +367,15 @@
      *
      * @return proxy port
      */
-    public int getPort() {
-        return mPort;
+    public int getProxyPort() {
+        return mProxyPort;
     }
     /**
-     * Returns the MMSC URL of the APN.
+     * Returns the MMSC Uri of the APN.
      *
-     * @return MMSC URL.
+     * @return MMSC Uri.
      */
-    public URL getMmsc() {
+    public Uri getMmsc() {
         return mMmsc;
     }
 
@@ -237,8 +384,8 @@
      *
      * @return MMS proxy address.
      */
-    public InetAddress getMmsProxy() {
-        return mMmsProxy;
+    public InetAddress getMmsProxyAddress() {
+        return mMmsProxyAddress;
     }
 
     /**
@@ -246,8 +393,8 @@
      *
      * @return MMS proxy port
      */
-    public int getMmsPort() {
-        return mMmsPort;
+    public int getMmsProxyPort() {
+        return mMmsProxyPort;
     }
 
     /**
@@ -268,21 +415,9 @@
         return mPassword;
     }
 
-    /** @hide */
-    @IntDef({
-            AUTH_TYPE_NONE,
-            AUTH_TYPE_PAP,
-            AUTH_TYPE_CHAP,
-            AUTH_TYPE_PAP_OR_CHAP,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface AuthType {}
-
     /**
      * Returns the authentication type of the APN.
      *
-     * Example of possible values: {@link #AUTH_TYPE_NONE}, {@link #AUTH_TYPE_PAP}.
-     *
      * @return authentication type
      */
     @AuthType
@@ -290,32 +425,20 @@
         return mAuthType;
     }
 
-    /** @hide */
-    @StringDef({
-            TYPE_DEFAULT,
-            TYPE_MMS,
-            TYPE_SUPL,
-            TYPE_DUN,
-            TYPE_HIPRI,
-            TYPE_FOTA,
-            TYPE_IMS,
-            TYPE_CBS,
-            TYPE_IA,
-            TYPE_EMERGENCY
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface ApnType {}
-
     /**
-     * Returns the list of APN types of the APN.
+     * Returns the bitmask of APN types.
      *
-     * Example of possible values: {@link #TYPE_DEFAULT}, {@link #TYPE_MMS}.
+     * <p>Apn types are usage categories for an APN entry. One APN entry may support multiple
+     * APN types, eg, a single APN may service regular internet traffic ("default") as well as
+     * MMS-specific connections.
      *
-     * @return the list of APN types
+     * <p>The bitmask of APN types is calculated from APN types defined in {@link ApnSetting}.
+     *
+     * @see Builder#setApnTypeBitmask(int)
+     * @return a bitmask describing the types of the APN
      */
-    @ApnType
-    public List<String> getTypes() {
-        return mTypes;
+    public @ApnType int getApnTypeBitmask() {
+        return mApnTypeBitmask;
     }
 
     /**
@@ -328,7 +451,7 @@
     }
 
     /**
-     * Returns the numeric operator ID for the APN. Usually
+     * Returns the numeric operator ID for the APN. Numeric operator ID is defined as
      * {@link android.provider.Telephony.Carriers#MCC} +
      * {@link android.provider.Telephony.Carriers#MNC}.
      *
@@ -338,37 +461,29 @@
         return mOperatorNumeric;
     }
 
-    /** @hide */
-    @StringDef({
-            PROTOCOL_IP,
-            PROTOCOL_IPV6,
-            PROTOCOL_IPV4V6,
-            PROTOCOL_PPP,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface ProtocolType {}
-
     /**
      * Returns the protocol to use to connect to this APN.
      *
-     * One of the {@code PDP_type} values in TS 27.007 section 10.1.1.
-     * Example of possible values: {@link #PROTOCOL_IP}, {@link #PROTOCOL_IPV6}.
+     * <p>Protocol is one of the {@code PDP_type} values in TS 27.007 section 10.1.1.
      *
+     * @see Builder#setProtocol(int)
      * @return the protocol
      */
     @ProtocolType
-    public String getProtocol() {
+    public int getProtocol() {
         return mProtocol;
     }
 
     /**
-     * Returns the protocol to use to connect to this APN when roaming.
+     * Returns the protocol to use to connect to this APN while the device is roaming.
      *
-     * The syntax is the same as {@link android.provider.Telephony.Carriers#PROTOCOL}.
+     * <p>Roaming protocol is one of the {@code PDP_type} values in TS 27.007 section 10.1.1.
      *
+     * @see Builder#setRoamingProtocol(int)
      * @return the roaming protocol
      */
-    public String getRoamingProtocol() {
+    @ProtocolType
+    public int getRoamingProtocol() {
         return mRoamingProtocol;
     }
 
@@ -398,41 +513,29 @@
         return mNetworkTypeBitmask;
     }
 
-    /** @hide */
-    @StringDef({
-            MVNO_TYPE_SPN,
-            MVNO_TYPE_IMSI,
-            MVNO_TYPE_GID,
-            MVNO_TYPE_ICCID,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface MvnoType {}
-
     /**
      * Returns the MVNO match type for this APN.
      *
-     * Example of possible values: {@link #MVNO_TYPE_SPN}, {@link #MVNO_TYPE_IMSI}.
-     *
+     * @see Builder#setMvnoType(int)
      * @return the MVNO match type
      */
     @MvnoType
-    public String getMvnoType() {
+    public int getMvnoType() {
         return mMvnoType;
     }
 
     private ApnSetting(Builder builder) {
         this.mEntryName = builder.mEntryName;
         this.mApnName = builder.mApnName;
-        this.mProxy = builder.mProxy;
-        this.mPort = builder.mPort;
+        this.mProxyAddress = builder.mProxyAddress;
+        this.mProxyPort = builder.mProxyPort;
         this.mMmsc = builder.mMmsc;
-        this.mMmsProxy = builder.mMmsProxy;
-        this.mMmsPort = builder.mMmsPort;
+        this.mMmsProxyAddress = builder.mMmsProxyAddress;
+        this.mMmsProxyPort = builder.mMmsProxyPort;
         this.mUser = builder.mUser;
         this.mPassword = builder.mPassword;
         this.mAuthType = builder.mAuthType;
-        this.mTypes = (builder.mTypes == null ? new ArrayList<String>() : builder.mTypes);
-        this.mTypesBitmap = builder.mTypesBitmap;
+        this.mApnTypeBitmask = builder.mApnTypeBitmask;
         this.mId = builder.mId;
         this.mOperatorNumeric = builder.mOperatorNumeric;
         this.mProtocol = builder.mProtocol;
@@ -451,25 +554,25 @@
 
     /** @hide */
     public static ApnSetting makeApnSetting(int id, String operatorNumeric, String entryName,
-            String apnName, InetAddress proxy, int port, URL mmsc, InetAddress mmsProxy,
-            int mmsPort, String user, String password, int authType, List<String> types,
-            String protocol, String roamingProtocol, boolean carrierEnabled,
+            String apnName, InetAddress proxy, int port, Uri mmsc, InetAddress mmsProxy,
+            int mmsPort, String user, String password, int authType, int mApnTypeBitmask,
+            int protocol, int roamingProtocol, boolean carrierEnabled,
             int networkTypeBitmask, int profileId, boolean modemCognitive, int maxConns,
-            int waitTime, int maxConnsTime, int mtu, String mvnoType, String mvnoMatchData) {
+            int waitTime, int maxConnsTime, int mtu, int mvnoType, String mvnoMatchData) {
         return new Builder()
                 .setId(id)
                 .setOperatorNumeric(operatorNumeric)
                 .setEntryName(entryName)
                 .setApnName(apnName)
-                .setProxy(proxy)
-                .setPort(port)
+                .setProxyAddress(proxy)
+                .setProxyPort(port)
                 .setMmsc(mmsc)
-                .setMmsProxy(mmsProxy)
-                .setMmsPort(mmsPort)
+                .setMmsProxyAddress(mmsProxy)
+                .setMmsProxyPort(mmsPort)
                 .setUser(user)
                 .setPassword(password)
                 .setAuthType(authType)
-                .setTypes(types)
+                .setApnTypeBitmask(mApnTypeBitmask)
                 .setProtocol(protocol)
                 .setRoamingProtocol(roamingProtocol)
                 .setCarrierEnabled(carrierEnabled)
@@ -487,7 +590,7 @@
 
     /** @hide */
     public static ApnSetting makeApnSetting(Cursor cursor) {
-        String[] types = parseTypes(
+        final int apnTypesBitmask = parseTypes(
                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE)));
         int networkTypeBitmask = cursor.getInt(
                 cursor.getColumnIndexOrThrow(Telephony.Carriers.NETWORK_TYPE_BITMASK));
@@ -507,7 +610,7 @@
                         cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY))),
                 portFromString(cursor.getString(
                         cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT))),
-                URLFromString(cursor.getString(
+                UriFromString(cursor.getString(
                         cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))),
                 inetAddressFromString(cursor.getString(
                         cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY))),
@@ -516,10 +619,12 @@
                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)),
                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)),
                 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)),
-                Arrays.asList(types),
-                cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)),
-                cursor.getString(cursor.getColumnIndexOrThrow(
-                        Telephony.Carriers.ROAMING_PROTOCOL)),
+                apnTypesBitmask,
+                nullToNotInMapInt(PROTOCOL_STRING_MAP.get(
+                    cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)))),
+                nullToNotInMapInt(PROTOCOL_STRING_MAP.get(
+                    cursor.getString(cursor.getColumnIndexOrThrow(
+                        Telephony.Carriers.ROAMING_PROTOCOL)))),
                 cursor.getInt(cursor.getColumnIndexOrThrow(
                         Telephony.Carriers.CARRIER_ENABLED)) == 1,
                 networkTypeBitmask,
@@ -531,8 +636,9 @@
                 cursor.getInt(cursor.getColumnIndexOrThrow(
                         Telephony.Carriers.MAX_CONNS_TIME)),
                 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)),
-                cursor.getString(cursor.getColumnIndexOrThrow(
-                        Telephony.Carriers.MVNO_TYPE)),
+                nullToNotInMapInt(MVNO_TYPE_STRING_MAP.get(
+                    cursor.getString(cursor.getColumnIndexOrThrow(
+                        Telephony.Carriers.MVNO_TYPE)))),
                 cursor.getString(cursor.getColumnIndexOrThrow(
                         Telephony.Carriers.MVNO_MATCH_DATA)));
     }
@@ -540,8 +646,8 @@
     /** @hide */
     public static ApnSetting makeApnSetting(ApnSetting apn) {
         return makeApnSetting(apn.mId, apn.mOperatorNumeric, apn.mEntryName, apn.mApnName,
-                apn.mProxy, apn.mPort, apn.mMmsc, apn.mMmsProxy, apn.mMmsPort, apn.mUser,
-                apn.mPassword, apn.mAuthType, apn.mTypes, apn.mProtocol, apn.mRoamingProtocol,
+                apn.mProxyAddress, apn.mProxyPort, apn.mMmsc, apn.mMmsProxyAddress, apn.mMmsProxyPort, apn.mUser,
+                apn.mPassword, apn.mAuthType, apn.mApnTypeBitmask, apn.mProtocol, apn.mRoamingProtocol,
                 apn.mCarrierEnabled, apn.mNetworkTypeBitmask, apn.mProfileId,
                 apn.mModemCognitive, apn.mMaxConns, apn.mWaitTime, apn.mMaxConnsTime, apn.mMtu,
                 apn.mMvnoType, apn.mMvnoMatchData);
@@ -555,18 +661,14 @@
                 .append(", ").append(mId)
                 .append(", ").append(mOperatorNumeric)
                 .append(", ").append(mApnName)
-                .append(", ").append(inetAddressToString(mProxy))
-                .append(", ").append(URLToString(mMmsc))
-                .append(", ").append(inetAddressToString(mMmsProxy))
-                .append(", ").append(portToString(mMmsPort))
-                .append(", ").append(portToString(mPort))
+                .append(", ").append(inetAddressToString(mProxyAddress))
+                .append(", ").append(UriToString(mMmsc))
+                .append(", ").append(inetAddressToString(mMmsProxyAddress))
+                .append(", ").append(portToString(mMmsProxyPort))
+                .append(", ").append(portToString(mProxyPort))
                 .append(", ").append(mAuthType).append(", ");
-        for (int i = 0; i < mTypes.size(); i++) {
-            sb.append(mTypes.get(i));
-            if (i < mTypes.size() - 1) {
-                sb.append(" | ");
-            }
-        }
+        final String[] types = deParseTypes(mApnTypeBitmask).split(",");
+        sb.append(TextUtils.join(" | ", types)).append(", ");
         sb.append(", ").append(mProtocol);
         sb.append(", ").append(mRoamingProtocol);
         sb.append(", ").append(mCarrierEnabled);
@@ -588,56 +690,37 @@
      * @hide
      */
     public boolean hasMvnoParams() {
-        return !TextUtils.isEmpty(mMvnoType) && !TextUtils.isEmpty(mMvnoMatchData);
+        return (mMvnoType != NOT_IN_MAP_INT) && !TextUtils.isEmpty(mMvnoMatchData);
     }
 
     /** @hide */
-    public boolean canHandleType(String type) {
-        if (!mCarrierEnabled) return false;
-        boolean wildcardable = true;
-        if (TYPE_IA.equalsIgnoreCase(type)) wildcardable = false;
-        for (String t : mTypes) {
-            // DEFAULT handles all, and HIPRI is handled by DEFAULT
-            if (t.equalsIgnoreCase(type)
-                    || (wildcardable && t.equalsIgnoreCase(TYPE_ALL))
-                    || (t.equalsIgnoreCase(TYPE_DEFAULT)
-                    && type.equalsIgnoreCase(TYPE_HIPRI))) {
-                return true;
-            }
-        }
-        return false;
+    public boolean canHandleType(@ApnType int type) {
+        return mCarrierEnabled && ((mApnTypeBitmask & type) == type);
     }
 
     // check whether the types of two APN same (even only one type of each APN is same)
     private boolean typeSameAny(ApnSetting first, ApnSetting second) {
         if (VDBG) {
             StringBuilder apnType1 = new StringBuilder(first.mApnName + ": ");
-            for (int index1 = 0; index1 < first.mTypes.size(); index1++) {
-                apnType1.append(first.mTypes.get(index1));
-                apnType1.append(",");
-            }
+            apnType1.append(deParseTypes(first.mApnTypeBitmask));
 
             StringBuilder apnType2 = new StringBuilder(second.mApnName + ": ");
-            for (int index1 = 0; index1 < second.mTypes.size(); index1++) {
-                apnType2.append(second.mTypes.get(index1));
-                apnType2.append(",");
-            }
+            apnType2.append(deParseTypes(second.mApnTypeBitmask));
+
             Rlog.d(LOG_TAG, "APN1: is " + apnType1);
             Rlog.d(LOG_TAG, "APN2: is " + apnType2);
         }
 
-        for (int index1 = 0; index1 < first.mTypes.size(); index1++) {
-            for (int index2 = 0; index2 < second.mTypes.size(); index2++) {
-                if (first.mTypes.get(index1).equals(ApnSetting.TYPE_ALL)
-                        || second.mTypes.get(index2).equals(ApnSetting.TYPE_ALL)
-                        || first.mTypes.get(index1).equals(second.mTypes.get(index2))) {
-                    if (VDBG) Rlog.d(LOG_TAG, "typeSameAny: return true");
-                    return true;
-                }
+        if ((first.mApnTypeBitmask & second.mApnTypeBitmask) != 0) {
+            if (VDBG) {
+                Rlog.d(LOG_TAG, "typeSameAny: return true");
             }
+            return true;
         }
 
-        if (VDBG) Rlog.d(LOG_TAG, "typeSameAny: return false");
+        if (VDBG) {
+            Rlog.d(LOG_TAG, "typeSameAny: return false");
+        }
         return false;
     }
 
@@ -655,16 +738,15 @@
                 && Objects.equals(mId, other.mId)
                 && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
                 && Objects.equals(mApnName, other.mApnName)
-                && Objects.equals(mProxy, other.mProxy)
+                && Objects.equals(mProxyAddress, other.mProxyAddress)
                 && Objects.equals(mMmsc, other.mMmsc)
-                && Objects.equals(mMmsProxy, other.mMmsProxy)
-                && Objects.equals(mMmsPort, other.mMmsPort)
-                && Objects.equals(mPort,other.mPort)
+                && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
+                && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
+                && Objects.equals(mProxyPort,other.mProxyPort)
                 && Objects.equals(mUser, other.mUser)
                 && Objects.equals(mPassword, other.mPassword)
                 && Objects.equals(mAuthType, other.mAuthType)
-                && Objects.equals(mTypes, other.mTypes)
-                && Objects.equals(mTypesBitmap, other.mTypesBitmap)
+                && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
                 && Objects.equals(mProtocol, other.mProtocol)
                 && Objects.equals(mRoamingProtocol, other.mRoamingProtocol)
                 && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
@@ -701,16 +783,15 @@
         return mEntryName.equals(other.mEntryName)
                 && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
                 && Objects.equals(mApnName, other.mApnName)
-                && Objects.equals(mProxy, other.mProxy)
+                && Objects.equals(mProxyAddress, other.mProxyAddress)
                 && Objects.equals(mMmsc, other.mMmsc)
-                && Objects.equals(mMmsProxy, other.mMmsProxy)
-                && Objects.equals(mMmsPort, other.mMmsPort)
-                && Objects.equals(mPort, other.mPort)
+                && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
+                && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
+                && Objects.equals(mProxyPort, other.mProxyPort)
                 && Objects.equals(mUser, other.mUser)
                 && Objects.equals(mPassword, other.mPassword)
                 && Objects.equals(mAuthType, other.mAuthType)
-                && Objects.equals(mTypes, other.mTypes)
-                && Objects.equals(mTypesBitmap, other.mTypesBitmap)
+                && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
                 && (isDataRoaming || Objects.equals(mProtocol,other.mProtocol))
                 && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol))
                 && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
@@ -736,17 +817,17 @@
                 && !other.canHandleType(TYPE_DUN)
                 && Objects.equals(this.mApnName, other.mApnName)
                 && !typeSameAny(this, other)
-                && xorEqualsInetAddress(this.mProxy, other.mProxy)
-                && xorEqualsPort(this.mPort, other.mPort)
+                && xorEquals(this.mProxyAddress, other.mProxyAddress)
+                && xorEqualsPort(this.mProxyPort, other.mProxyPort)
                 && xorEquals(this.mProtocol, other.mProtocol)
                 && xorEquals(this.mRoamingProtocol, other.mRoamingProtocol)
                 && Objects.equals(this.mCarrierEnabled, other.mCarrierEnabled)
                 && Objects.equals(this.mProfileId, other.mProfileId)
                 && Objects.equals(this.mMvnoType, other.mMvnoType)
                 && Objects.equals(this.mMvnoMatchData, other.mMvnoMatchData)
-                && xorEqualsURL(this.mMmsc, other.mMmsc)
-                && xorEqualsInetAddress(this.mMmsProxy, other.mMmsProxy)
-                && xorEqualsPort(this.mMmsPort, other.mMmsPort))
+                && xorEquals(this.mMmsc, other.mMmsc)
+                && xorEquals(this.mMmsProxyAddress, other.mMmsProxyAddress)
+                && xorEqualsPort(this.mMmsProxyPort, other.mMmsProxyPort))
                 && Objects.equals(this.mNetworkTypeBitmask, other.mNetworkTypeBitmask);
     }
 
@@ -757,42 +838,23 @@
                 || TextUtils.isEmpty(second));
     }
 
-    // Equal or one is not specified.
-    private boolean xorEqualsInetAddress(InetAddress first, InetAddress second) {
-        return first == null || second == null || first.equals(second);
-    }
-
-    // Equal or one is not specified.
-    private boolean xorEqualsURL(URL first, URL second) {
+    // Equal or one is not null.
+    private boolean xorEquals(Object first, Object second) {
         return first == null || second == null || first.equals(second);
     }
 
     // Equal or one is not specified.
     private boolean xorEqualsPort(int first, int second) {
-        return first == -1 || second == -1 || Objects.equals(first, second);
+        return first == NO_PORT_SPECIFIED || second == NO_PORT_SPECIFIED
+            || Objects.equals(first, second);
     }
 
-    // Helper function to convert APN string into a 32-bit bitmask.
-    private static int getApnBitmask(String apn) {
-        switch (apn) {
-            case TYPE_DEFAULT: return ApnTypes.DEFAULT;
-            case TYPE_MMS: return ApnTypes.MMS;
-            case TYPE_SUPL: return ApnTypes.SUPL;
-            case TYPE_DUN: return ApnTypes.DUN;
-            case TYPE_HIPRI: return ApnTypes.HIPRI;
-            case TYPE_FOTA: return ApnTypes.FOTA;
-            case TYPE_IMS: return ApnTypes.IMS;
-            case TYPE_CBS: return ApnTypes.CBS;
-            case TYPE_IA: return ApnTypes.IA;
-            case TYPE_EMERGENCY: return ApnTypes.EMERGENCY;
-            case TYPE_ALL: return ApnTypes.ALL;
-            default: return ApnTypes.NONE;
-        }
-    }
-
-    private String deParseTypes(List<String> types) {
-        if (types == null) {
-            return null;
+    private String deParseTypes(int apnTypeBitmask) {
+        List<String> types = new ArrayList<>();
+        for (Integer type : APN_TYPE_INT_MAP.keySet()) {
+            if ((apnTypeBitmask & type) == type) {
+                types.add(APN_TYPE_INT_MAP.get(type));
+            }
         }
         return TextUtils.join(",", types);
     }
@@ -808,21 +870,25 @@
         apnValue.put(Telephony.Carriers.NUMERIC, nullToEmpty(mOperatorNumeric));
         apnValue.put(Telephony.Carriers.NAME, nullToEmpty(mEntryName));
         apnValue.put(Telephony.Carriers.APN, nullToEmpty(mApnName));
-        apnValue.put(Telephony.Carriers.PROXY, mProxy == null ? "" : inetAddressToString(mProxy));
-        apnValue.put(Telephony.Carriers.PORT, portToString(mPort));
-        apnValue.put(Telephony.Carriers.MMSC, mMmsc == null ? "" : URLToString(mMmsc));
-        apnValue.put(Telephony.Carriers.MMSPORT, portToString(mMmsPort));
-        apnValue.put(Telephony.Carriers.MMSPROXY, mMmsProxy == null
-                ? "" : inetAddressToString(mMmsProxy));
+        apnValue.put(Telephony.Carriers.PROXY, mProxyAddress == null ? ""
+            : inetAddressToString(mProxyAddress));
+        apnValue.put(Telephony.Carriers.PORT, portToString(mProxyPort));
+        apnValue.put(Telephony.Carriers.MMSC, mMmsc == null ? "" : UriToString(mMmsc));
+        apnValue.put(Telephony.Carriers.MMSPORT, portToString(mMmsProxyPort));
+        apnValue.put(Telephony.Carriers.MMSPROXY, mMmsProxyAddress == null
+                ? "" : inetAddressToString(mMmsProxyAddress));
         apnValue.put(Telephony.Carriers.USER, nullToEmpty(mUser));
         apnValue.put(Telephony.Carriers.PASSWORD, nullToEmpty(mPassword));
         apnValue.put(Telephony.Carriers.AUTH_TYPE, mAuthType);
-        String apnType = deParseTypes(mTypes);
+        String apnType = deParseTypes(mApnTypeBitmask);
         apnValue.put(Telephony.Carriers.TYPE, nullToEmpty(apnType));
-        apnValue.put(Telephony.Carriers.PROTOCOL, nullToEmpty(mProtocol));
-        apnValue.put(Telephony.Carriers.ROAMING_PROTOCOL, nullToEmpty(mRoamingProtocol));
+        apnValue.put(Telephony.Carriers.PROTOCOL,
+            nullToEmpty(PROTOCOL_INT_MAP.get(mProtocol)));
+        apnValue.put(Telephony.Carriers.ROAMING_PROTOCOL,
+            nullToEmpty(PROTOCOL_INT_MAP.get(mRoamingProtocol)));
         apnValue.put(Telephony.Carriers.CARRIER_ENABLED, mCarrierEnabled);
-        apnValue.put(Telephony.Carriers.MVNO_TYPE, nullToEmpty(mMvnoType));
+        apnValue.put(Telephony.Carriers.MVNO_TYPE,
+            nullToEmpty(MVNO_TYPE_INT_MAP.get(mMvnoType)));
         apnValue.put(Telephony.Carriers.NETWORK_TYPE_BITMASK, mNetworkTypeBitmask);
 
         return apnValue;
@@ -830,32 +896,31 @@
 
     /**
      * @param types comma delimited list of APN types
-     * @return array of APN types
+     * @return bitmask of APN types
      * @hide
      */
-    public static String[] parseTypes(String types) {
-        String[] result;
-        // If unset, set to DEFAULT.
+    public static int parseTypes(String types) {
+        // If unset, set to ALL.
         if (TextUtils.isEmpty(types)) {
-            result = new String[1];
-            result[0] = TYPE_ALL;
+            return TYPE_ALL_BUT_IA;
         } else {
-            result = types.split(",");
-        }
-        return result;
-    }
-
-    private static URL URLFromString(String url) {
-        try {
-            return TextUtils.isEmpty(url) ? null : new URL(url);
-        } catch (MalformedURLException e) {
-            Log.e(LOG_TAG, "Can't parse URL from string.");
-            return null;
+            int result = 0;
+            for (String str : types.split(",")) {
+                Integer type = APN_TYPE_STRING_MAP.get(str);
+                if (type != null) {
+                    result |= type;
+                }
+            }
+            return result;
         }
     }
 
-    private static String URLToString(URL url) {
-        return url == null ? "" : url.toString();
+    private static Uri UriFromString(String uri) {
+        return TextUtils.isEmpty(uri) ? null : Uri.parse(uri);
+    }
+
+    private static String UriToString(Uri uri) {
+        return uri == null ? "" : uri.toString();
     }
 
     private static InetAddress inetAddressFromString(String inetAddress) {
@@ -887,7 +952,7 @@
     }
 
     private static int portFromString(String strPort) {
-        int port = -1;
+        int port = NO_PORT_SPECIFIED;
         if (!TextUtils.isEmpty(strPort)) {
             try {
                 port = Integer.parseInt(strPort);
@@ -899,7 +964,7 @@
     }
 
     private static String portToString(int port) {
-        return port == -1 ? "" : Integer.toString(port);
+        return port == NO_PORT_SPECIFIED ? "" : Integer.toString(port);
     }
 
     // Implement Parcelable.
@@ -916,19 +981,19 @@
         dest.writeString(mOperatorNumeric);
         dest.writeString(mEntryName);
         dest.writeString(mApnName);
-        dest.writeValue(mProxy);
-        dest.writeInt(mPort);
+        dest.writeValue(mProxyAddress);
+        dest.writeInt(mProxyPort);
         dest.writeValue(mMmsc);
-        dest.writeValue(mMmsProxy);
-        dest.writeInt(mMmsPort);
+        dest.writeValue(mMmsProxyAddress);
+        dest.writeInt(mMmsProxyPort);
         dest.writeString(mUser);
         dest.writeString(mPassword);
         dest.writeInt(mAuthType);
-        dest.writeStringArray(mTypes.toArray(new String[0]));
-        dest.writeString(mProtocol);
-        dest.writeString(mRoamingProtocol);
+        dest.writeInt(mApnTypeBitmask);
+        dest.writeInt(mProtocol);
+        dest.writeInt(mRoamingProtocol);
         dest.writeInt(mCarrierEnabled ? 1: 0);
-        dest.writeString(mMvnoType);
+        dest.writeInt(mMvnoType);
         dest.writeInt(mNetworkTypeBitmask);
     }
 
@@ -939,23 +1004,23 @@
         final String apnName = in.readString();
         final InetAddress proxy = (InetAddress)in.readValue(InetAddress.class.getClassLoader());
         final int port = in.readInt();
-        final URL mmsc = (URL)in.readValue(URL.class.getClassLoader());
+        final Uri mmsc = (Uri)in.readValue(Uri.class.getClassLoader());
         final InetAddress mmsProxy = (InetAddress)in.readValue(InetAddress.class.getClassLoader());
         final int mmsPort = in.readInt();
         final String user = in.readString();
         final String password = in.readString();
         final int authType = in.readInt();
-        final List<String> types = Arrays.asList(in.readStringArray());
-        final String protocol = in.readString();
-        final String roamingProtocol = in.readString();
+        final int apnTypesBitmask = in.readInt();
+        final int protocol = in.readInt();
+        final int roamingProtocol = in.readInt();
         final boolean carrierEnabled = in.readInt() > 0;
-        final String mvnoType = in.readString();
+        final int mvnoType = in.readInt();
         final int networkTypeBitmask = in.readInt();
 
         return makeApnSetting(id, operatorNumeric, entryName, apnName,
-                proxy, port, mmsc, mmsProxy, mmsPort, user, password, authType, types, protocol,
-                roamingProtocol, carrierEnabled, networkTypeBitmask, 0, false,
-                0, 0, 0, 0, mvnoType, null);
+            proxy, port, mmsc, mmsProxy, mmsPort, user, password, authType, apnTypesBitmask,
+            protocol, roamingProtocol, carrierEnabled, networkTypeBitmask, 0, false,
+            0, 0, 0, 0, mvnoType, null);
     }
 
     public static final Parcelable.Creator<ApnSetting> CREATOR =
@@ -971,89 +1036,26 @@
                 }
             };
 
-    /**
-     * APN types for data connections.  These are usage categories for an APN
-     * entry.  One APN entry may support multiple APN types, eg, a single APN
-     * may service regular internet traffic ("default") as well as MMS-specific
-     * connections.<br/>
-     * ALL is a special type to indicate that this APN entry can
-     * service all data connections.
-     */
-    public static final String TYPE_ALL = "*";
-    /** APN type for default data traffic */
-    public static final String TYPE_DEFAULT = "default";
-    /** APN type for MMS traffic */
-    public static final String TYPE_MMS = "mms";
-    /** APN type for SUPL assisted GPS */
-    public static final String TYPE_SUPL = "supl";
-    /** APN type for DUN traffic */
-    public static final String TYPE_DUN = "dun";
-    /** APN type for HiPri traffic */
-    public static final String TYPE_HIPRI = "hipri";
-    /** APN type for FOTA */
-    public static final String TYPE_FOTA = "fota";
-    /** APN type for IMS */
-    public static final String TYPE_IMS = "ims";
-    /** APN type for CBS */
-    public static final String TYPE_CBS = "cbs";
-    /** APN type for IA Initial Attach APN */
-    public static final String TYPE_IA = "ia";
-    /** APN type for Emergency PDN. This is not an IA apn, but is used
-     * for access to carrier services in an emergency call situation. */
-    public static final String TYPE_EMERGENCY = "emergency";
-    /**
-     * Array of all APN types
-     *
-     * @hide
-     */
-    public static final String[] ALL_TYPES = {
-            TYPE_DEFAULT,
-            TYPE_MMS,
-            TYPE_SUPL,
-            TYPE_DUN,
-            TYPE_HIPRI,
-            TYPE_FOTA,
-            TYPE_IMS,
-            TYPE_CBS,
-            TYPE_IA,
-            TYPE_EMERGENCY
-    };
-
-    // Possible values for authentication types.
-    public static final int AUTH_TYPE_NONE = 0;
-    public static final int AUTH_TYPE_PAP = 1;
-    public static final int AUTH_TYPE_CHAP = 2;
-    public static final int AUTH_TYPE_PAP_OR_CHAP = 3;
-
-    // Possible values for protocol.
-    public static final String PROTOCOL_IP = "IP";
-    public static final String PROTOCOL_IPV6 = "IPV6";
-    public static final String PROTOCOL_IPV4V6 = "IPV4V6";
-    public static final String PROTOCOL_PPP = "PPP";
-
-    // Possible values for MVNO type.
-    public static final String MVNO_TYPE_SPN = "spn";
-    public static final String MVNO_TYPE_IMSI = "imsi";
-    public static final String MVNO_TYPE_GID = "gid";
-    public static final String MVNO_TYPE_ICCID = "iccid";
+    private static int nullToNotInMapInt(Integer value) {
+        return value == null ? NOT_IN_MAP_INT : value;
+    }
 
     public static class Builder{
         private String mEntryName;
         private String mApnName;
-        private InetAddress mProxy;
-        private int mPort = -1;
-        private URL mMmsc;
-        private InetAddress mMmsProxy;
-        private int mMmsPort = -1;
+        private InetAddress mProxyAddress;
+        private int mProxyPort = NO_PORT_SPECIFIED;
+        private Uri mMmsc;
+        private InetAddress mMmsProxyAddress;
+        private int mMmsProxyPort = NO_PORT_SPECIFIED;
         private String mUser;
         private String mPassword;
         private int mAuthType;
-        private List<String> mTypes;
-        private int mTypesBitmap;
+        private int mApnTypeBitmask;
         private int mId;
         private String mOperatorNumeric;
-        private String mProtocol;
-        private String mRoamingProtocol;
+        private int mProtocol = NOT_IN_MAP_INT;
+        private int mRoamingProtocol = NOT_IN_MAP_INT;
         private int mMtu;
         private int mNetworkTypeBitmask;
         private boolean mCarrierEnabled;
@@ -1062,7 +1064,7 @@
         private int mMaxConns;
         private int mWaitTime;
         private int mMaxConnsTime;
-        private String mMvnoType;
+        private int mMvnoType = NOT_IN_MAP_INT;
         private String mMvnoMatchData;
 
         /**
@@ -1182,8 +1184,8 @@
          *
          * @param proxy the proxy address to set for the APN
          */
-        public Builder setProxy(InetAddress proxy) {
-            this.mProxy = proxy;
+        public Builder setProxyAddress(InetAddress proxy) {
+            this.mProxyAddress = proxy;
             return this;
         }
 
@@ -1192,17 +1194,17 @@
          *
          * @param port the proxy port to set for the APN
          */
-        public Builder setPort(int port) {
-            this.mPort = port;
+        public Builder setProxyPort(int port) {
+            this.mProxyPort = port;
             return this;
         }
 
         /**
-         * Sets the MMSC URL of the APN.
+         * Sets the MMSC Uri of the APN.
          *
-         * @param mmsc the MMSC URL to set for the APN
+         * @param mmsc the MMSC Uri to set for the APN
          */
-        public Builder setMmsc(URL mmsc) {
+        public Builder setMmsc(Uri mmsc) {
             this.mMmsc = mmsc;
             return this;
         }
@@ -1212,8 +1214,8 @@
          *
          * @param mmsProxy the MMS proxy address to set for the APN
          */
-        public Builder setMmsProxy(InetAddress mmsProxy) {
-            this.mMmsProxy = mmsProxy;
+        public Builder setMmsProxyAddress(InetAddress mmsProxy) {
+            this.mMmsProxyAddress = mmsProxy;
             return this;
         }
 
@@ -1222,8 +1224,8 @@
          *
          * @param mmsPort the MMS proxy port to set for the APN
          */
-        public Builder setMmsPort(int mmsPort) {
-            this.mMmsPort = mmsPort;
+        public Builder setMmsProxyPort(int mmsPort) {
+            this.mMmsProxyPort = mmsPort;
             return this;
         }
 
@@ -1251,8 +1253,6 @@
         /**
          * Sets the authentication type of the APN.
          *
-         * Example of possible values: {@link #AUTH_TYPE_NONE}, {@link #AUTH_TYPE_PAP}.
-         *
          * @param authType the authentication type to set for the APN
          */
         public Builder setAuthType(@AuthType int authType) {
@@ -1261,25 +1261,25 @@
         }
 
         /**
-         * Sets the list of APN types of the APN.
+         * Sets the bitmask of APN types.
          *
-         * Example of possible values: {@link #TYPE_DEFAULT}, {@link #TYPE_MMS}.
+         * <p>Apn types are usage categories for an APN entry. One APN entry may support multiple
+         * APN types, eg, a single APN may service regular internet traffic ("default") as well as
+         * MMS-specific connections.
          *
-         * @param types the list of APN types to set for the APN
+         * <p>The bitmask of APN types is calculated from APN types defined in {@link ApnSetting}.
+         *
+         * @param apnTypeBitmask a bitmask describing the types of the APN
          */
-        public Builder setTypes(@ApnType List<String> types) {
-            this.mTypes = types;
-            int apnBitmap = 0;
-            for (int i = 0; i < mTypes.size(); i++) {
-                mTypes.set(i, mTypes.get(i).toLowerCase());
-                apnBitmap |= getApnBitmask(mTypes.get(i));
-            }
-            this.mTypesBitmap = apnBitmap;
+        public Builder setApnTypeBitmask(@ApnType int apnTypeBitmask) {
+            this.mApnTypeBitmask = apnTypeBitmask;
             return this;
         }
 
         /**
-         * Set the numeric operator ID for the APN.
+         * Sets the numeric operator ID for the APN. Numeric operator ID is defined as
+         * {@link android.provider.Telephony.Carriers#MCC} +
+         * {@link android.provider.Telephony.Carriers#MNC}.
          *
          * @param operatorNumeric the numeric operator ID to set for this entry
          */
@@ -1291,22 +1291,23 @@
         /**
          * Sets the protocol to use to connect to this APN.
          *
-         * One of the {@code PDP_type} values in TS 27.007 section 10.1.1.
-         * Example of possible values: {@link #PROTOCOL_IP}, {@link #PROTOCOL_IPV6}.
+         * <p>Protocol is one of the {@code PDP_type} values in TS 27.007 section 10.1.1.
          *
          * @param protocol the protocol to set to use to connect to this APN
          */
-        public Builder setProtocol(@ProtocolType String protocol) {
+        public Builder setProtocol(@ProtocolType int protocol) {
             this.mProtocol = protocol;
             return this;
         }
 
         /**
-         * Sets the protocol to use to connect to this APN when roaming.
+         * Sets the protocol to use to connect to this APN when the device is roaming.
+         *
+         * <p>Roaming protocol is one of the {@code PDP_type} values in TS 27.007 section 10.1.1.
          *
          * @param roamingProtocol the protocol to set to use to connect to this APN when roaming
          */
-        public Builder setRoamingProtocol(String roamingProtocol) {
+        public Builder setRoamingProtocol(@ProtocolType  int roamingProtocol) {
             this.mRoamingProtocol = roamingProtocol;
             return this;
         }
@@ -1334,16 +1335,25 @@
         /**
          * Sets the MVNO match type for this APN.
          *
-         * Example of possible values: {@link #MVNO_TYPE_SPN}, {@link #MVNO_TYPE_IMSI}.
-         *
          * @param mvnoType the MVNO match type to set for this APN
          */
-        public Builder setMvnoType(@MvnoType String mvnoType) {
+        public Builder setMvnoType(@MvnoType int mvnoType) {
             this.mMvnoType = mvnoType;
             return this;
         }
 
+        /**
+         * Builds {@link ApnSetting} from this builder.
+         *
+         * @return {@code null} if {@link #setApnName(String)} or {@link #setEntryName(String)}
+         * is empty, or {@link #setApnTypeBitmask(int)} doesn't contain a valid bit,
+         * {@link ApnSetting} built from this builder otherwise.
+         */
         public ApnSetting build() {
+            if ((mApnTypeBitmask & ApnTypes.ALL) == 0 || TextUtils.isEmpty(mApnName)
+                || TextUtils.isEmpty(mEntryName)) {
+                return null;
+            }
             return new ApnSetting(this);
         }
     }
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 1637c55..dff1c6f 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -15,11 +15,12 @@
  */
 package android.telephony.euicc;
 
+import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
-import android.annotation.TestApi;
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -73,6 +74,7 @@
      */
     @SystemApi
     @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public static final String ACTION_OTA_STATUS_CHANGED =
             "android.telephony.euicc.action.OTA_STATUS_CHANGED";
 
@@ -301,6 +303,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public int getOtaStatus() {
         if (!isEnabled()) {
             return EUICC_OTA_STATUS_UNAVAILABLE;
@@ -325,6 +328,7 @@
      * @param switchAfterDownload if true, the profile will be activated upon successful download.
      * @param callbackIntent a PendingIntent to launch when the operation completes.
      */
+    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void downloadSubscription(DownloadableSubscription subscription,
             boolean switchAfterDownload, PendingIntent callbackIntent) {
         if (!isEnabled()) {
@@ -387,6 +391,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void continueOperation(Intent resolutionIntent, Bundle resolutionExtras) {
         if (!isEnabled()) {
             PendingIntent callbackIntent =
@@ -422,6 +427,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void getDownloadableSubscriptionMetadata(
             DownloadableSubscription subscription, PendingIntent callbackIntent) {
         if (!isEnabled()) {
@@ -452,6 +458,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void getDefaultDownloadableSubscriptionList(PendingIntent callbackIntent) {
         if (!isEnabled()) {
             sendUnavailableError(callbackIntent);
@@ -496,6 +503,7 @@
      * @param subscriptionId the ID of the subscription to delete.
      * @param callbackIntent a PendingIntent to launch when the operation completes.
      */
+    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void deleteSubscription(int subscriptionId, PendingIntent callbackIntent) {
         if (!isEnabled()) {
             sendUnavailableError(callbackIntent);
@@ -523,6 +531,7 @@
      *     current profile without activating another profile to replace it.
      * @param callbackIntent a PendingIntent to launch when the operation completes.
      */
+    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void switchToSubscription(int subscriptionId, PendingIntent callbackIntent) {
         if (!isEnabled()) {
             sendUnavailableError(callbackIntent);
@@ -548,6 +557,7 @@
      * @param callbackIntent a PendingIntent to launch when the operation completes.
      * @hide
      */
+    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void updateSubscriptionNickname(
             int subscriptionId, String nickname, PendingIntent callbackIntent) {
         if (!isEnabled()) {
@@ -566,12 +576,13 @@
      * Erase all subscriptions and reset the eUICC.
      *
      * <p>Requires that the calling app has the
-     * {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. This is for
-     * internal system use only.
+     * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
      *
      * @param callbackIntent a PendingIntent to launch when the operation completes.
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void eraseSubscriptions(PendingIntent callbackIntent) {
         if (!isEnabled()) {
             sendUnavailableError(callbackIntent);